// cloneMsgArg is used when the split buffer scenario has the pubArg in the existing read buffer, // but // we need to hold onto it into the next read. private void cloneMsgArg() { ps.argBuf = ByteBuffer.wrap(ps.argBufStore); // System.err.printf("ps.argBuf 1= %s\n", ps.argBuf); ps.argBuf.put(ps.ma.subject, 0, ps.ma.subjectLength); // System.err.printf("ps.argBuf 2= %s\n", ps.argBuf); if (ps.ma.replyLength != 0) { ps.argBuf.put(ps.ma.reply, 0, ps.ma.replyLength); } // System.err.printf("ps.argBuf 3= %s\n", ps.argBuf); ps.argBuf.rewind(); ps.argBuf.get(ps.ma.subject, 0, ps.ma.subjectLength); if (ps.ma.replyLength != 0) { ps.argBuf.get(ps.ma.reply, 0, ps.ma.replyLength); } // ps.argBuf.flip(); // System.err.printf("ps.argBuf 4= %s\n", ps.argBuf); }
protected void parse(byte[] buf, int len) throws ParseException { int i; byte b; boolean error = false; // if (len > buf.length) { // throw new ParseException(String.format("Parse length(%d) > actual buffer length(%d)\n", // len, buf.length),0); // } // String tmpStr = new String(buf, 0, len); // System.err.printf("##### Parsing buf=[%s], ps.argBuf=[%s]\n", tmpStr.trim(), ps.argBuf); for (i = 0; i < len; i++) { b = buf[i]; // printStatus(buf, i); switch (ps.state) { case OP_START: switch (b) { case 'M': case 'm': ps.state = NatsOp.OP_M; break; case 'P': case 'p': ps.state = NatsOp.OP_P; break; case '+': ps.state = NatsOp.OP_PLUS; break; case '-': ps.state = NatsOp.OP_MINUS; break; default: error = true; break; } break; case OP_M: switch (b) { case 'S': case 's': ps.state = NatsOp.OP_MS; break; default: error = true; break; } break; case OP_MS: switch (b) { case 'G': case 'g': ps.state = NatsOp.OP_MSG; break; default: error = true; break; } break; case OP_MSG: switch (b) { case ' ': case '\t': ps.state = NatsOp.OP_MSG_SPC; break; default: error = true; break; } break; case OP_MSG_SPC: switch (b) { case ' ': case '\t': continue; default: ps.state = NatsOp.MSG_ARG; ps.as = i; break; } break; case MSG_ARG: switch (b) { case '\r': ps.drop = 1; break; case '\n': ByteBuffer arg = null; if (ps.argBuf != null) { // End of args arg = ps.argBuf; arg.flip(); processMsgArgs(arg.array(), arg.arrayOffset(), arg.limit()); } else { // arg = ByteBuffer.wrap(buf, ps.as, // i-ps.drop-ps.as).slice(); processMsgArgs(buf, ps.as, i - ps.drop - ps.as); } // System.err.printf("arrayOffset=%d, length=%d\n", // arg.arrayOffset(), arg.limit()); // processMsgArgs(arg.array(), arg.arrayOffset(), arg.limit()); ps.drop = 0; ps.as = i + 1; ps.state = NatsOp.MSG_PAYLOAD; // jump ahead with the index. If this overruns // what is left we fall out and process split // buffer. i = ps.as + ps.ma.size - 1; break; default: // We have a leftover argBuf we'll continuing filling if (ps.argBuf != null) { try { ps.argBuf.put(b); } catch (Exception e) { System.err.printf("i=%d, b=%c, ps.argBuf=%s\n", i, (char) b, ps.argBuf); e.printStackTrace(); } } break; } break; case MSG_PAYLOAD: boolean done = false; // System.err.printf("MSG_PAYLOAD: ps.ma.size = %d\n", ps.ma.size); // System.err.printf("ps.msgBuf.position=%d, i=%d, ps.as=%d, // ps.ma.size=%d\n", // ps.msgBuf.position(), i, ps.as, ps.ma.size); if (ps.msgBuf != null) { // System.err.printf("ps.msgBuf.position=%d, i=%d, ps.as=%d, // ps.ma.size=%d\n", // ps.msgBuf.position(), i, ps.as, ps.ma.size); // Already have bytes in the buffer if (ps.msgBuf.position() >= ps.ma.size) { ps.msgBuf.flip(); nc.processMsg(ps.msgBuf.array(), 0, ps.msgBuf.limit()); done = true; } else { // copy as much as we can to the buffer and skip ahead. int toCopy = ps.ma.size - ps.msgBuf.limit(); int avail = len - i; if (avail < toCopy) { toCopy = avail; } // System.err.printf("msgBuf=%s(remaining=%d), i=%d, len=%d, // ps.ma.size=%d, avail = %d, toCopy=%d," // + " buf.length=%d\n", // ps.msgBuf, ps.msgBuf.remaining(), i, len, ps.ma.size, avail, // toCopy, buf.length); if (toCopy > 0) { // System.err.printf("msgBuf=%s(remaining=%d), i=%d, len=%d, // ps.ma.size=%d, avail = %d, toCopy=%d," // + " buf.length=%d\n", // ps.msgBuf, ps.msgBuf.remaining(), i, len, ps.ma.size, avail, // toCopy, buf.length); ps.msgBuf.put(buf, i, toCopy); // Update our index i += toCopy - 1; } else { ps.msgBuf.put(b); } } } else if (i - ps.as >= ps.ma.size) { // System.err.printf("i=%d, ps.as=%d, ps.ma.size=%d\n", i, ps.as, // ps.ma.size); // If we are at or past the end of the payload, go ahead and process it, no // buffering needed. nc.processMsg(buf, ps.as, i - ps.as); // pass offset and length done = true; } if (done) { ps.argBuf = null; // ps.argBuf.clear(); ps.msgBuf = null; // ps.msgBuf.clear(); ps.state = NatsOp.MSG_END; } break; case MSG_END: switch (b) { case '\n': ps.drop = 0; ps.as = i + 1; ps.state = NatsOp.OP_START; break; default: continue; } break; case OP_PLUS: switch (b) { case 'O': case 'o': ps.state = NatsOp.OP_PLUS_O; break; default: error = true; break; } break; case OP_PLUS_O: switch (b) { case 'K': case 'k': ps.state = NatsOp.OP_PLUS_OK; break; default: error = true; break; } break; case OP_PLUS_OK: switch (b) { case '\n': nc.processOK(); ps.drop = 0; ps.state = NatsOp.OP_START; break; } break; case OP_MINUS: switch (b) { case 'E': case 'e': ps.state = NatsOp.OP_MINUS_E; break; default: error = true; break; } break; case OP_MINUS_E: switch (b) { case 'R': case 'r': ps.state = NatsOp.OP_MINUS_ER; break; default: error = true; break; } break; case OP_MINUS_ER: switch (b) { case 'R': case 'r': ps.state = NatsOp.OP_MINUS_ERR; break; default: error = true; break; } break; case OP_MINUS_ERR: switch (b) { case ' ': case '\t': ps.state = NatsOp.OP_MINUS_ERR_SPC; break; default: error = true; break; } break; case OP_MINUS_ERR_SPC: switch (b) { case ' ': case '\t': continue; default: ps.state = NatsOp.MINUS_ERR_ARG; ps.as = i; break; } break; case MINUS_ERR_ARG: switch (b) { case '\r': ps.drop = 1; break; case '\n': ByteBuffer arg = null; if (ps.argBuf != null) { arg = ps.argBuf; ps.argBuf = null; } else { arg = ByteBuffer.wrap(buf, ps.as, i - ps.as); } nc.processErr(arg); ps.drop = 0; ps.as = i + 1; ps.state = NatsOp.OP_START; break; default: if (ps.argBuf != null) { ps.argBuf.put(b); } break; } break; case OP_P: switch (b) { case 'I': case 'i': ps.state = NatsOp.OP_PI; break; case 'O': case 'o': ps.state = NatsOp.OP_PO; break; default: error = true; break; } break; case OP_PO: switch (b) { case 'N': case 'n': ps.state = NatsOp.OP_PON; break; default: // parseError(buf, i); error = true; break; } break; case OP_PON: switch (b) { case 'G': case 'g': ps.state = NatsOp.OP_PONG; break; default: error = true; break; } break; case OP_PONG: switch (b) { case '\n': nc.processPong(); ps.drop = 0; ps.state = NatsOp.OP_START; break; default: break; } break; case OP_PI: switch (b) { case 'N': case 'n': ps.state = NatsOp.OP_PIN; break; default: error = true; break; } break; case OP_PIN: switch (b) { case 'G': case 'g': ps.state = NatsOp.OP_PING; break; default: error = true; break; } break; case OP_PING: switch (b) { case '\n': nc.processPing(); ps.drop = 0; ps.state = NatsOp.OP_START; break; } break; default: error = true; break; } // switch(ps.state) if (error) { error = false; throw new ParseException( String.format("nats: parse error [%s]: '%s'", ps.state, new String(buf, i, len - i)), i); } // System.err.printf("After processing index %d, ps.state=%s\n", i, ps.state ); } // for // We have processed the entire buffer // Check for split buffer scenarios if ((ps.state == NatsOp.MSG_ARG || ps.state == NatsOp.MINUS_ERR_ARG) && (ps.argBuf == null)) { ps.argBuf = ByteBuffer.wrap(ps.argBufStore); ps.argBuf.put(buf, ps.as, i - ps.drop - ps.as); // System.err.printf("split msg, no clone, ps.argBuf=%s\n", ps.argBuf); // FIXME, check max len } // Check for split msg if (ps.state == NatsOp.MSG_PAYLOAD && ps.msgBuf == null) { // We need to clone the msgArg if it is still referencing the // read buffer and we are not able to process the msg. if (ps.argBuf == null) { cloneMsgArg(); // System.err.printf("split msg, after clone, ps.argBuf=%s\n", ps.argBuf); } // If we will overflow the scratch buffer, just create a // new buffer to hold the split message. int lrem = len - ps.as; // portion of msg remaining in buffer if (ps.ma.size > ps.msgBufStore.length) { ps.msgBufStore = new byte[ps.ma.size]; } ps.msgBuf = ByteBuffer.wrap(ps.msgBufStore); // copy what's left in the buffer ps.msgBuf.put(buf, ps.as, lrem); } }