static AJ_Status AuthAdvance(AJ_SASL_Context* context, AJ_IOBuffer* rxBuf, AJ_IOBuffer* txBuf) { AJ_Status status = AJ_OK; AJ_InfoPrintf(("AuthAdvance(context=0x%p, rxBuf=0x%p, txBuf=0x%p)\n", context, rxBuf, txBuf)); if (context->state != AJ_SASL_SEND_AUTH_REQ) { /* * All the authentication messages end in a CR/LF so read until we get a newline */ while ((AJ_IO_BUF_AVAIL(rxBuf) == 0) || (*(rxBuf->writePtr - 1) != '\n')) { status = rxBuf->recv(rxBuf, AJ_IO_BUF_SPACE(rxBuf), 3500); if (status != AJ_OK) { break; } } } if (status == AJ_OK) { uint32_t inLen = AJ_IO_BUF_AVAIL(rxBuf); *rxBuf->writePtr = '\0'; status = AJ_SASL_Advance(context, (char*)rxBuf->readPtr, (char*)txBuf->writePtr, AJ_IO_BUF_SPACE(txBuf)); if (status == AJ_OK) { rxBuf->readPtr += inLen; txBuf->writePtr += strlen((char*)txBuf->writePtr); status = txBuf->send(txBuf); } } return status; }
/* * Make sure we have the required number of bytes in the I/O buffer */ static AJ_Status LoadBytes(AJ_IOBuffer* ioBuf, uint16_t numBytes, uint8_t pad) { AJ_Status status = AJ_OK; numBytes += pad; /* * Needs to be enough headroom in the buffer to satisfy the read */ if (numBytes > (ioBuf->bufSize - AJ_IO_BUF_CONSUMED(ioBuf))) { return AJ_ERR_RESOURCES; } while (AJ_IO_BUF_AVAIL(ioBuf) < numBytes) { //#pragma calls = AJ_Net_Recv status = ioBuf->recv(ioBuf, numBytes - AJ_IO_BUF_AVAIL(ioBuf), UNMARSHAL_TIMEOUT); if (status != AJ_OK) { /* * Timeouts after we have started to unmarshal a message are a bad sign. */ if (status == AJ_ERR_TIMEOUT) { status = AJ_ERR_READ; } break; } } /* * Skip over pad bytes (The wire protocol says these should be zeroes) */ ioBuf->readPtr += pad; return status; }
static AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { DWORD ret; DWORD tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); if (tx > 0) { NetContext* ctx = (NetContext*) buf->context; WSAOVERLAPPED ov; DWORD flags = 0; WSABUF wsbuf; memset(&ov, 0, sizeof(ov)); ov.hEvent = sendEvent; wsbuf.len = tx; wsbuf.buf = buf->readPtr; ret = WSASend(ctx->tcpSock, &wsbuf, 1, NULL, flags, &ov, NULL); if (!WSAGetOverlappedResult(ctx->tcpSock, &ov, &tx, TRUE, &flags)) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. WSAGetLastError()=0x%x, status=AJ_ERR_WRITE\n", WSAGetLastError())); return AJ_ERR_WRITE; } buf->readPtr += tx; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; }
//----------------------------------------------------------------------------- AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { uint32_t ret; uint32_t tx = AJ_IO_BUF_AVAIL(buf); printf("AJ_Net_Send(buf=0x%p)\n", buf); // printf("tcp_client_socket=%d", tcp_client_socket); if (tx > 0) { // ret = g_client.write(buf->readPtr, tx); send(tcp_client_socket, buf->readPtr, tx, 0); // while(tcp_tx_ready==0) m2m_wifi_handle_events(NULL); /* if (ret != 0) { //AJ_ErrPrintf(("AJ_Net_Send(): send() failed. error=%d, status=AJ_ERR_WRITE\n", g_client.getWriteError())); return AJ_ERR_WRITE; }*/ buf->readPtr += tcp_tx_ready; tcp_tx_ready=0; } // if (AJ_IO_BUF_AVAIL(buf) == 0) // { AJ_IO_BUF_RESET(buf); // } //printf("AJ_Net_Send end\n"); return AJ_OK; }
AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { int ret; uint32_t tx = AJ_IO_BUF_AVAIL(buf); //AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); if (tx > 0) { ret = sendto(rx_socket, buf->readPtr, tx, 0, (struct sockaddr *)&addr, sizeof(addr)); m2m_wifi_handle_events(NULL); //AJ_InfoPrintf(("AJ_Net_SendTo(): SendTo write %d\n", ret)); if (sock_tx_state != 1) { //AJ_ErrPrintf(("AJ_Net_Sendto(): no bytes. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } buf->readPtr += ret; } AJ_IO_BUF_RESET(buf); //AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; }
AJ_Status AJ_CloseMsg(AJ_Message* msg) { AJ_Status status = AJ_OK; /* * This function is idempotent */ if (msg->bus) { AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; /* * Skip any unconsumed bytes */ while (msg->bodyBytes) { uint16_t sz = AJ_IO_BUF_AVAIL(ioBuf); sz = min(sz, msg->bodyBytes); if (!sz) { AJ_IO_BUF_RESET(ioBuf); sz = min(msg->bodyBytes, ioBuf->bufSize); } status = LoadBytes(ioBuf, sz, 0); if (status != AJ_OK) { break; } msg->bodyBytes -= sz; ioBuf->readPtr += sz; } memset(msg, 0, sizeof(AJ_Message)); #ifndef NDEBUG currentMsg = NULL; #endif } return status; }
AJ_Status AJ_Net_Send(AJ_IOBuffer* buf) { uint32_t ret; uint32_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_Send(buf=0x%p)\n", buf)); if (tx > 0) { ret = g_client.write(buf->readPtr, tx); if (ret == 0) { AJ_ErrPrintf(("AJ_Net_Send(): send() failed. error=%d, status=AJ_ERR_WRITE\n", g_client.getWriteError())); return AJ_ERR_WRITE; } buf->readPtr += ret; } if (AJ_IO_BUF_AVAIL(buf) == 0) { AJ_IO_BUF_RESET(buf); } AJ_InfoPrintf(("AJ_Net_Send(): status=AJ_OK\n")); return AJ_OK; }
static AJ_Status ReadLine(AJ_IOBuffer* rxBuf) { /* * All the authentication messages end in a CR/LF so read until we get a newline */ AJ_Status status = AJ_OK; while ((AJ_IO_BUF_AVAIL(rxBuf) == 0) || (*(rxBuf->writePtr - 1) != '\n')) { status = rxBuf->recv(rxBuf, AJ_IO_BUF_SPACE(rxBuf), 3500); if (status != AJ_OK) { break; } } return status; }
void AJ_IOBufRebase(AJ_IOBuffer* ioBuf, size_t preserve) { int32_t unconsumed = AJ_IO_BUF_AVAIL(ioBuf); /* * Move any unconsumed data to the start of the I/O buffer */ if (unconsumed) { memmove(ioBuf->bufStart + preserve, ioBuf->readPtr, unconsumed); } ioBuf->readPtr = ioBuf->bufStart + preserve; ioBuf->writePtr = ioBuf->bufStart + preserve + unconsumed; }
static AJ_Status TxFunc(AJ_IOBuffer* buf) { size_t tx = AJ_IO_BUF_AVAIL(buf);; if ((wireBytes + tx) > sizeof(wireBuffer)) { return AJ_ERR_WRITE; } else { memcpy(wireBuffer + wireBytes, buf->bufStart, tx); AJ_IO_BUF_RESET(buf); wireBytes += tx; return AJ_OK; } }
AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { int ret; uint32_t tx = AJ_IO_BUF_AVAIL(buf); AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); if (tx > 0) { // send to subnet-directed broadcast address #ifdef WIFI_UDP_WORKING IPAddress subnet = WiFi.subnetMask(); IPAddress localIp = WiFi.localIP(); #else IPAddress subnet = Ethernet.subnetMask(); IPAddress localIp = Ethernet.localIP(); #endif uint32_t directedBcastAddr = (uint32_t(subnet) & uint32_t(localIp)) | (~uint32_t(subnet)); IPAddress a(directedBcastAddr); ret = g_clientUDP.beginPacket(IPAddress(directedBcastAddr), AJ_UDP_PORT); AJ_InfoPrintf(("AJ_Net_SendTo(): beginPacket to %d.%d.%d.%d, result = %d\n", a[0], a[1], a[2], a[3], ret)); if (ret == 0) { AJ_InfoPrintf(("AJ_Net_SendTo(): no sender\n")); } ret = g_clientUDP.write(buf->readPtr, tx); AJ_InfoPrintf(("AJ_Net_SendTo(): SendTo write %d\n", ret)); if (ret == 0) { AJ_ErrPrintf(("AJ_Net_Sendto(): no bytes. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } buf->readPtr += ret; ret = g_clientUDP.endPacket(); if (ret == 0) { AJ_ErrPrintf(("AJ_Net_Sendto(): endPacket() error. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; }
AJ_Status AJ_ARDP_UDP_Connect(AJ_BusAttachment* bus, void* context, const AJ_Service* service, AJ_NetSocket* netSock) { AJ_Message hello; AJ_GUID localGuid; char guid_buf[33]; AJ_Status status; AJ_Message helloResponse; AJ_GetLocalGUID(&localGuid); AJ_GUID_ToString(&localGuid, guid_buf, sizeof(guid_buf)); AJ_MarshalMethodCall(bus, &hello, AJ_METHOD_BUS_SIMPLE_HELLO, AJ_BusDestination, 0, AJ_FLAG_ALLOW_REMOTE_MSG, AJ_UDP_CONNECT_TIMEOUT); AJ_MarshalArgs(&hello, "su", guid_buf, 10); hello.hdr->bodyLen = hello.bodyBytes; status = AJ_ARDP_Connect(bus->sock.tx.readPtr, AJ_IO_BUF_AVAIL(&bus->sock.tx), context, netSock); if (status != AJ_OK) { return status; } status = AJ_UnmarshalMsg(bus, &helloResponse, AJ_UDP_CONNECT_TIMEOUT); if (status == AJ_OK && helloResponse.msgId == AJ_REPLY_ID(AJ_METHOD_BUS_SIMPLE_HELLO)) { if (helloResponse.hdr->msgType == AJ_MSG_ERROR) { status = AJ_ERR_CONNECT; } else { AJ_Arg uniqueName, protoVersion; AJ_UnmarshalArg(&helloResponse, &uniqueName); AJ_SkipArg(&helloResponse); AJ_UnmarshalArg(&helloResponse, &protoVersion); /** * The two most-significant bits are reserved for the nameType, * which we don't currently care about in the thin client */ routingProtoVersion = (uint8_t) ((*protoVersion.val.v_uint32) & 0x3FFFFFFF); if (uniqueName.len >= (sizeof(bus->uniqueName) - 1)) { AJ_ErrPrintf(("AJ_ARDP_Connect(): AJ_ERR_RESOURCES\n")); status = AJ_ERR_RESOURCES; } else { memcpy(bus->uniqueName, uniqueName.val.v_string, uniqueName.len); bus->uniqueName[uniqueName.len] = '\0'; } /AJ_InfoPrintf(("Received name: %s and version %u\n", bus->uniqueName, routingProtoVersion)); if (routingProtoVersion < AJ_GetMinProtoVersion()) { AJ_InfoPrintf(("AJ_ARDP_Connect(): Blacklisting routing node, found %u but require >= %u\n", routingProtoVersion, AJ_GetMinProtoVersion())); AddRoutingNodeToBlacklist(service); status = AJ_ERR_CONNECT; } } }
static void ResetRead(AJ_IOBuffer* rxBuf) { rxBuf->readPtr += AJ_IO_BUF_AVAIL(rxBuf); *rxBuf->writePtr = '\0'; }
static AJ_Status ParseIsAt(AJ_IOBuffer* rxBuf, const char* prefix, AJ_Service* service) { AJ_Status status = AJ_ERR_NO_MATCH; size_t preLen = strlen(prefix); NSHeader* hdr = (NSHeader*)rxBuf->readPtr; uint32_t len = AJ_IO_BUF_AVAIL(rxBuf); uint8_t* p = rxBuf->readPtr + 4; uint8_t* eod = (uint8_t*)hdr + len; AJ_InfoPrintf(("ParseIsAt(rxbuf=0x%p, prefix=\"%s\", service=0x%p)\n", rxBuf, prefix, service)); service->addrTypes = 0; /* * Silently ignore versions we don't know how to parse */ if (MSG_VERSION(hdr->version) != MSG_V1) { return status; } /* * Questions come in first - we currently ignore them */ while (hdr->qCount--) { uint8_t flags = *p++; uint8_t nameCount = *p++; /* * Questions must be WHO_HAS messages */ if (MSG_TYPE(flags) != WHO_HAS_MSG) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } while (nameCount--) { uint8_t sz = *p++; p += sz; if (p > eod) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_END_OF_DATA\n")); status = AJ_ERR_END_OF_DATA; goto Exit; } } } /* * Now the answers - this is what we are looking for */ while (hdr->aCount--) { uint8_t flags = *p++; uint8_t nameCount = *p++; /* * Answers must be IS_AT messages */ if (MSG_TYPE(flags) != IS_AT_MSG) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_INVALID\n")); return AJ_ERR_INVALID; } /* * Must be reliable IPV4 or IPV6 */ if (!(flags & (R4_FLAG | R6_FLAG))) { return status; } /* * Get transport mask */ service->transportMask = (p[0] << 8) | p[1]; p += 2; /* * Decode addresses */ if (flags & R4_FLAG) { memcpy(&service->ipv4, p, sizeof(service->ipv4)); p += sizeof(service->ipv4); service->ipv4port = (p[0] << 8) | p[1]; p += 2; service->addrTypes |= AJ_ADDR_IPV4; } if (flags & U4_FLAG) { p += sizeof(service->ipv4) + 2; } if (flags & R6_FLAG) { memcpy(&service->ipv6, p, sizeof(service->ipv6)); p += sizeof(service->ipv6); service->ipv6port = (p[0] << 8) | p[1]; p += 2; service->addrTypes |= AJ_ADDR_IPV6; } if (flags & U6_FLAG) { p += sizeof(service->ipv6) + 2; } /* * Skip guid if it's present */ if (flags & G_FLAG) { uint8_t sz = *p++; len -= 1 + sz; p += sz; } if (p >= eod) { AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_END_OF_DATA\n")); return AJ_ERR_END_OF_DATA; } /* * Iterate over the names */ while (nameCount--) { uint8_t sz = *p++; { char sav = p[sz]; p[sz] = 0; AJ_InfoPrintf(("ParseIsAt(): Found \"%s\" IP 0x%x\n", p, service->addrTypes)); p[sz] = sav; } if ((preLen <= sz) && (memcmp(p, prefix, preLen) == 0)) { status = AJ_OK; goto Exit; } p += sz; if (p > eod) { status = AJ_ERR_END_OF_DATA; AJ_InfoPrintf(("ParseIsAt(): AJ_ERR_END_OF_DATA\n")); goto Exit; } } } Exit: return status; }
static AJ_Status AJ_Net_SendTo(AJ_IOBuffer* buf) { DWORD ret; DWORD tx = AJ_IO_BUF_AVAIL(buf); int numWrites = 0; AJ_InfoPrintf(("AJ_Net_SendTo(buf=0x%p)\n", buf)); assert(buf->direction == AJ_IO_BUF_TX); assert(NumMcastSocks > 0); if (tx > 0) { size_t i; // our router (hopefully) lives on one of the networks but we don't know which one. // send discovery requests to all of them. for (i = 0; i < NumMcastSocks; ++i) { SOCKET sock = McastSocks[i].sock; int family = McastSocks[i].family; if ((buf->flags & AJ_IO_BUF_AJ) && !McastSocks[i].is_mdns) { // try sending IPv6 multicast if (family == AF_INET6) { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(struct sockaddr_in6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(AJ_UDP_PORT); inet_pton(AF_INET6, AJ_IPV6_MULTICAST_GROUP, &sin6.sin6_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin6, sizeof(struct sockaddr_in6)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (IPV6). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv4 multicast if (family == AF_INET && McastSocks[i].has_mcast4) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(AJ_UDP_PORT); inet_pton(AF_INET, AJ_IPV4_MULTICAST_GROUP, &sin.sin_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (IPV4). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv4 subnet broadcast if (family == AF_INET && McastSocks[i].v4_bcast.s_addr) { struct sockaddr_in bsin; memset(&bsin, 0, sizeof(bsin)); bsin.sin_family = AF_INET; bsin.sin_port = htons(AJ_UDP_PORT); bsin.sin_addr.s_addr = McastSocks[i].v4_bcast.s_addr; ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &bsin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (bcast). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } } if ((buf->flags & AJ_IO_BUF_MDNS) && McastSocks[i].is_mdns) { // Update the packet with receiver info for this socket if (RewriteSenderInfo(buf, ntohl(McastSocks[i].v4_addr.s_addr), McastSocks[i].recv_port) != AJ_OK) { AJ_WarnPrintf(("AJ_Net_SendTo(): RewriteSenderInfo failed.\n")); continue; } tx = AJ_IO_BUF_AVAIL(buf); // try sending IPv4 multicast if (family == AF_INET && McastSocks[i].has_mcast4) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(MDNS_UDP_PORT); inet_pton(AF_INET, MDNS_IPV4_MULTICAST_GROUP, &sin.sin_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() multicast failed (IPV4). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv4 subnet broadcast if (family == AF_INET && McastSocks[i].v4_bcast.s_addr) { struct sockaddr_in bsin; memset(&bsin, 0, sizeof(bsin)); bsin.sin_family = AF_INET; bsin.sin_port = htons(MDNS_UDP_PORT); bsin.sin_addr.s_addr = McastSocks[i].v4_bcast.s_addr; ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &bsin, sizeof(struct sockaddr_in)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() broadcast failed. WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } // try sending IPv6 multicast if (family == AF_INET6) { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(struct sockaddr_in6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(MDNS_UDP_PORT); inet_pton(AF_INET6, MDNS_IPV6_MULTICAST_GROUP, &sin6.sin6_addr); ret = sendto(sock, buf->readPtr, tx, 0, (struct sockaddr*) &sin6, sizeof(struct sockaddr_in6)); if (ret == SOCKET_ERROR) { AJ_ErrPrintf(("AJ_Net_SendTo(): sendto() failed (IPV6). WSAGetLastError()=0x%x\n", WSAGetLastError())); } else { ++numWrites; } } } } if (numWrites == 0) { AJ_ErrPrintf(("AJ_Net_SendTo(): Did not sendto() at least one socket. status=AJ_ERR_WRITE\n")); return AJ_ERR_WRITE; } buf->readPtr += ret; } AJ_IO_BUF_RESET(buf); AJ_InfoPrintf(("AJ_Net_SendTo(): status=AJ_OK\n")); return AJ_OK; }
static AJ_Status RewriteSenderInfo(AJ_IOBuffer* buf, uint32_t addr, uint16_t port) { size_t tx = AJ_IO_BUF_AVAIL(buf); uint16_t sidVal; const char send[4] = { 'd', 'n', 'e', 's' }; const char sid[] = { 's', 'i', 'd', '=' }; const char ipv4[] = { 'i', 'p', 'v', '4', '=' }; const char upcv4[] = { 'u', 'p', 'c', 'v', '4', '=' }; char sidStr[6]; char ipv4Str[17]; char upcv4Str[6]; uint8_t* pkt; uint16_t dataLength; int match; AJ_Status status; // first, pluck the search ID from the mDNS header sidVal = *(buf->readPtr) << 8; sidVal += *(buf->readPtr + 1); // convert to strings status = AJ_IntToString((int32_t) sidVal, sidStr, sizeof(sidStr)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_IntToString((int32_t) port, upcv4Str, sizeof(upcv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } status = AJ_InetToString(addr, ipv4Str, sizeof(ipv4Str)); if (status != AJ_OK) { return AJ_ERR_WRITE; } // ASSUMPTIONS: sender-info resource record is the final resource record in the packet. // sid, ipv4, and upcv4 key value pairs are the final three key/value pairs in the record. // The length of the other fields in the record are static. // // search backwards through packet to find the start of "sender-info" pkt = buf->writePtr; match = 0; do { if (*(pkt--) == send[match]) { match++; } else { match = 0; } } while (pkt != buf->readPtr && match != 4); if (match != 4) { return AJ_ERR_WRITE; } // move forward to the Data Length field pkt += 22; // actual data length is the length of the static values already in the buffer plus // the three dynamic key-value pairs to re-write dataLength = 23 + 1 + sizeof(sid) + strlen(sidStr) + 1 + sizeof(ipv4) + strlen(ipv4Str) + 1 + sizeof(upcv4) + strlen(upcv4Str); *pkt++ = (dataLength >> 8) & 0xFF; *pkt++ = dataLength & 0xFF; // move forward past the static key-value pairs pkt += 23; // ASSERT: must be at the start of "sid=" assert(*(pkt + 1) == 's'); // re-write new values *pkt++ = sizeof(sid) + strlen(sidStr); memcpy(pkt, sid, sizeof(sid)); pkt += sizeof(sid); memcpy(pkt, sidStr, strlen(sidStr)); pkt += strlen(sidStr); *pkt++ = sizeof(ipv4) + strlen(ipv4Str); memcpy(pkt, ipv4, sizeof(ipv4)); pkt += sizeof(ipv4); memcpy(pkt, ipv4Str, strlen(ipv4Str)); pkt += strlen(ipv4Str); *pkt++ = sizeof(upcv4) + strlen(upcv4Str); memcpy(pkt, upcv4, sizeof(upcv4)); pkt += sizeof(upcv4); memcpy(pkt, upcv4Str, strlen(upcv4Str)); pkt += strlen(upcv4Str); buf->writePtr = pkt; return AJ_OK; }
AJ_Status AJ_UnmarshalRaw(AJ_Message* msg, const void** data, size_t len, size_t* actual) { AJ_Status status; size_t sz; AJ_IOBuffer* ioBuf = &msg->bus->sock.rx; /* * A soon as we start marshaling raw the header will become invalid so NULL it out */ if (msg->hdr) { uint8_t typeId = msg->signature[msg->sigOffset]; uint8_t pad; /* * There must be arguments to unmarshal */ if (!typeId) { return AJ_ERR_SIGNATURE; } /* * There may be padding before the argument */ pad = PadForType(typeId, ioBuf); if (pad > msg->bodyBytes) { return AJ_ERR_UNMARSHAL; } LoadBytes(ioBuf, 0, pad); msg->bodyBytes -= pad; /* * Standard signature matching is now meaningless */ msg->signature = ""; msg->sigOffset = 0; msg->hdr = NULL; } /* * Return an error if caller is attempting read off the end of the body */ if (len > msg->bodyBytes) { return AJ_ERR_UNMARSHAL; } /* * We want to return the requested data as contiguous bytes if possible */ sz = AJ_IO_BUF_AVAIL(ioBuf); if (sz < len) { AJ_IOBufRebase(ioBuf); } /* * If we try to load more than the buffer size we will get an error */ status = LoadBytes(ioBuf, (uint16_t)min(len, ioBuf->bufSize), 0); if (status == AJ_OK) { sz = AJ_IO_BUF_AVAIL(ioBuf); if (sz < len) { len = sz; } *data = ioBuf->readPtr; *actual = len; ioBuf->readPtr += len; msg->bodyBytes -= (uint16_t)len; } return status; }
AJ_Status AJ_UnmarshalMsg(AJ_BusAttachment* bus, AJ_Message* msg, uint32_t timeout) { AJ_Status status; AJ_IOBuffer* ioBuf = &bus->sock.rx; uint8_t* endOfHeader; uint32_t hdrPad; /* * Clear message then set the bus */ memset(msg, 0, sizeof(AJ_Message)); msg->msgId = AJ_INVALID_MSG_ID; msg->bus = bus; /* * Move any unconsumed data to the start of the I/O buffer */ AJ_IOBufRebase(ioBuf); /* * Load the message header */ while (AJ_IO_BUF_AVAIL(ioBuf) < sizeof(AJ_MsgHeader)) { //#pragma calls = AJ_Net_Recv status = ioBuf->recv(ioBuf, sizeof(AJ_MsgHeader) - AJ_IO_BUF_AVAIL(ioBuf), timeout); if (status != AJ_OK) { /* * If there were no messages to receive check if we have any methods call that have * timed-out and if so generate an internal error message to allow the application to * proceed. */ if ((status == AJ_ERR_TIMEOUT) && AJ_TimedOutMethodCall(msg)) { msg->hdr = (AJ_MsgHeader*)&internalErrorHdr; msg->error = AJ_ErrTimeout; msg->sender = AJ_GetUniqueName(msg->bus); msg->destination = msg->sender; status = AJ_OK; } return status; } } /* * Header was unmarsalled directly into the rx buffer */ msg->hdr = (AJ_MsgHeader*)ioBuf->bufStart; ioBuf->readPtr += sizeof(AJ_MsgHeader); /* * Quick sanity check on the header - unrecoverable error if this check fails */ if ((msg->hdr->endianess != AJ_LITTLE_ENDIAN) && (msg->hdr->endianess != AJ_BIG_ENDIAN)) { return AJ_ERR_READ; } /* * Endian swap header info - conventiently they are contiguous in the header */ EndianSwap(msg, AJ_ARG_INT32, &msg->hdr->bodyLen, 3); msg->bodyBytes = msg->hdr->bodyLen; /* * The header is null padded to an 8 bytes boundary */ hdrPad = (8 - msg->hdr->headerLen) & 7; /* * Load the header */ status = LoadBytes(ioBuf, msg->hdr->headerLen + hdrPad, 0); if (status != AJ_OK) { return status; } #ifndef NDEBUG /* * Check that messages are getting closed */ AJ_ASSERT(!currentMsg); currentMsg = msg; #endif /* * Assume an empty signature */ msg->signature = ""; /* * We have the header in the buffer now we can unmarshal the header fields */ endOfHeader = ioBuf->bufStart + sizeof(AJ_MsgHeader) + msg->hdr->headerLen; while (ioBuf->readPtr < endOfHeader) { const char* fieldSig; uint8_t fieldId; AJ_Arg hdrVal; /* * Custom unmarshal the header field - signature is "(yv)" so starts off with STRUCT aligment. */ status = LoadBytes(ioBuf, 4, PadForType(AJ_ARG_STRUCT, ioBuf)); if (status != AJ_OK) { break; } fieldId = ioBuf->readPtr[0]; fieldSig = (const char*)&ioBuf->readPtr[2]; ioBuf->readPtr += 4; /* * Now unmarshal the field value */ status = Unmarshal(msg, &fieldSig, &hdrVal); if (status != AJ_OK) { break; } /* * Check the field has the type we expect - we ignore fields we don't know */ if ((fieldId <= AJ_HDR_SESSION_ID) && (TypeForHdr[fieldId] != hdrVal.typeId)) { status = AJ_ERR_UNMARSHAL; break; } /* * Set the field value in the message */ switch (fieldId) { case AJ_HDR_OBJ_PATH: msg->objPath = hdrVal.val.v_objPath; break; case AJ_HDR_INTERFACE: msg->iface = hdrVal.val.v_string; break; case AJ_HDR_MEMBER: msg->member = hdrVal.val.v_string; break; case AJ_HDR_ERROR_NAME: msg->error = hdrVal.val.v_string; break; case AJ_HDR_REPLY_SERIAL: msg->replySerial = *(hdrVal.val.v_uint32); break; case AJ_HDR_DESTINATION: msg->destination = hdrVal.val.v_string; break; case AJ_HDR_SENDER: msg->sender = hdrVal.val.v_string; break; case AJ_HDR_SIGNATURE: msg->signature = hdrVal.val.v_signature; break; case AJ_HDR_TIMESTAMP: msg->timestamp = *(hdrVal.val.v_uint32); break; case AJ_HDR_TIME_TO_LIVE: msg->ttl = *(hdrVal.val.v_uint32); break; case AJ_HDR_SESSION_ID: msg->sessionId = *(hdrVal.val.v_uint32); break; case AJ_HDR_HANDLES: case AJ_HDR_COMPRESSION_TOKEN: default: /* Ignored */ break; } } if (status == AJ_OK) { AJ_ASSERT(ioBuf->readPtr == endOfHeader); /* * Consume the header pad bytes. */ ioBuf->readPtr += hdrPad; /* * If the message is encrypted load the entire message body and decrypt it. */ if (msg->hdr->flags & AJ_FLAG_ENCRYPTED) { status = LoadBytes(ioBuf, msg->hdr->bodyLen, 0); if (status == AJ_OK) { status = DecryptMessage(msg); } } /* * Toggle the AUTO_START flag so in the API no flags == 0 * * Note we must do this after decrypting the message or message authentication will fail. */ msg->hdr->flags ^= AJ_FLAG_AUTO_START; /* * If the message looks good try to identify it. */ if (status == AJ_OK) { status = AJ_IdentifyMessage(msg); } } else { /* * Consume entire header */ ioBuf->readPtr = endOfHeader + hdrPad; } if (status == AJ_OK) { AJ_DumpMsg("RECEIVED", msg, FALSE); } else { /* * Silently discard message unless in debug mode */ AJ_ErrPrintf(("Discarding bad message %s\n", AJ_StatusText(status))); AJ_DumpMsg("DISCARDING", msg, FALSE); AJ_CloseMsg(msg); } return status; }