Annotation of libaitmqtt/src/conn.c, revision 1.1.1.1.2.3
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.1.1.1.2.3! misho 6: * $Id: conn.c,v 1.1.1.1.2.2 2012/04/26 12:33:14 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.1.1.1.2.1 misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * mqtt_msgCONNECT() Create CONNECT message
51: *
52: * @buf = Message buffer
53: * @csConnID = ConnectID
1.1.1.1.2.3! misho 54: * @kasec = Keep alive timeout, if =0 default timeout for MQTT
1.1 misho 55: * @csUser = Username if !=NULL
56: * @csPass = Password for Username, only if csUser is set
57: * @csWillTopic = Will Topic if !=NULL Will Flags set into message
58: * @csWillMessage = Will Message, may be NULL
59: * @ClrSess = Clear Session subscriptions after disconnect
60: * @WillQOS = Will QOS if csWillTopic is set
61: * @WillRetain = Will Retain Will Message if csWillTopic is set
62: * return: -1 error or >-1 message size for send
63: */
64: int
65: mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const char *csConnID,
66: u_short kasec, const char *csUser, const char *csPass,
67: const char *csWillTopic, const char *csWillMessage,
68: u_char ClrSess, u_char WillQOS, u_char WillRetain)
69: {
1.1.1.1.2.3! misho 70: int n, len, siz = 0;
1.1 misho 71: struct mqtthdr *hdr;
72: mqtthdr_var_t *var, *cid, *topic, *wmsg, *user, *pass;
73: mqtthdr_protover_t *proto;
74: mqtthdr_connflgs_t *flags;
75: mqtt_len_t *ka;
1.1.1.1.2.3! misho 76: void *data;
1.1 misho 77:
78: if (!buf || !csConnID)
79: return -1;
1.1.1.1.2.3! misho 80: else
! 81: data = buf->msg_base;
1.1 misho 82: if (strlen(csConnID) > 23) {
1.1.1.1.2.1 misho 83: mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max 23 bytes)");
1.1 misho 84: return -1;
85: }
86: if (csUser && strlen(csUser) > 12) {
1.1.1.1.2.1 misho 87: mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max 12 bytes)");
1.1 misho 88: return -1;
89: }
90: if (csPass && strlen(csPass) > 12) {
1.1.1.1.2.1 misho 91: mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max 12 bytes)");
1.1 misho 92: return -1;
93: }
94: if (WillQOS > MQTT_QOS_EXACTLY) {
1.1.1.1.2.1 misho 95: mqtt_SetErr(EINVAL, "Invalid argument WillQOS - unknown QOS value");
1.1 misho 96: return -1;
97: }
98:
1.1.1.1.2.3! misho 99: /* calculate message size */
! 100: len = 10 + sizeof(mqtt_len_t); /* connect arguments */
! 101: len += sizeof(mqtt_len_t) + strlen(csConnID); /* connect id */
! 102: if (csUser && *csUser) { /* user/pass */
! 103: len += sizeof(mqtt_len_t) + strlen(csUser);
! 104: if (csPass)
! 105: len += sizeof(mqtt_len_t) + strlen(csPass);
! 106: }
! 107: if (csWillTopic && *csWillTopic) { /* will messages */
! 108: len += sizeof(mqtt_len_t) + strlen(csWillTopic);
! 109: len += sizeof(mqtt_len_t) + strlen(csWillMessage);
! 110: }
! 111:
! 112: /* calculate header size */
! 113: siz = sizeof(struct mqtthdr); /* mqtt fixed header */
! 114: n = mqtt_encodeLen(len); /* message size */
! 115: siz += mqtt_sizeLen(n) - 1; /* length size */
! 116:
! 117: if (mqtt_msgRealloc(buf, siz + len) == -1)
1.1 misho 118: return -1;
1.1.1.1.2.3! misho 119: else
! 120: hdr = (struct mqtthdr *) data;
1.1 misho 121:
122: /* fixed header */
123: MQTTHDR_MSGINIT(hdr);
124: hdr->mqtt_msg.type = MQTT_TYPE_CONNECT;
1.1.1.1.2.3! misho 125: *(u_int*) hdr->mqtt_len = n;
! 126: data += siz;
1.1 misho 127:
128: /* variable header */
1.1.1.1.2.3! misho 129: var = (mqtthdr_var_t*) data;
! 130: var->var_sb.val = htons(strlen(MQTT_CONN_STR));
! 131: memcpy(var->var_data, MQTT_CONN_STR, ntohs(var->var_sb.val));
! 132: data += MQTTHDR_VAR_SIZEOF(var);
1.1 misho 133:
1.1.1.1.2.3! misho 134: /* protocol version */
! 135: proto = (mqtthdr_protover_t*) data++;
1.1 misho 136: *proto = MQTT_PROTO_VER;
137:
138: /* CONNECT header */
1.1.1.1.2.3! misho 139: flags = (mqtthdr_connflgs_t*) data++;
1.1 misho 140: flags->clean_sess = ClrSess ? 1 : 0;
141: if (csUser && *csUser) {
142: flags->username = 1;
143: flags->password = csPass ? 1 : 0;
144: } else {
145: flags->username = 0;
146: flags->password = 0;
147: }
148: if (csWillTopic && *csWillTopic) {
149: flags->will_flg = 1;
150: flags->will_qos = WillQOS;
151: flags->will_retain = WillRetain ? 1 : 0;
152: } else {
153: flags->will_flg = 0;
154: flags->will_qos = 0;
155: flags->will_retain = 0;
156: }
157:
1.1.1.1.2.3! misho 158: /* keep alive */
! 159: ka = (mqtt_len_t*) data;
1.1 misho 160: ka->val = kasec ? htons(kasec) : htons(MQTT_KEEPALIVE);
1.1.1.1.2.3! misho 161: data += sizeof(mqtt_len_t);
1.1 misho 162:
163: /* ConnID */
1.1.1.1.2.3! misho 164: cid = (mqtthdr_var_t*) data;
1.1 misho 165: cid->var_sb.val = htons(strlen(csConnID));
166: memcpy(cid->var_data, csConnID, ntohs(cid->var_sb.val));
1.1.1.1.2.3! misho 167: data += MQTTHDR_VAR_SIZEOF(cid);
1.1 misho 168:
169: /* If Will Flags setup */
170: if (csWillTopic && *csWillTopic) {
1.1.1.1.2.3! misho 171: topic = (mqtthdr_var_t*) data;
1.1 misho 172: topic->var_sb.val = htons(strlen(csWillTopic));
173: memcpy(topic->var_data, csWillTopic, ntohs(topic->var_sb.val));
1.1.1.1.2.3! misho 174: data += MQTTHDR_VAR_SIZEOF(topic);
1.1 misho 175:
1.1.1.1.2.3! misho 176: wmsg = (mqtthdr_var_t*) data;
1.1 misho 177: if (csWillMessage && *csWillMessage) {
178: wmsg->var_sb.val = htons(strlen(csWillMessage));
179: memcpy(wmsg->var_data, csWillMessage, ntohs(wmsg->var_sb.val));
180: } else
181: wmsg->var_sb.val = 0;
1.1.1.1.2.3! misho 182: data += MQTTHDR_VAR_SIZEOF(wmsg);
1.1 misho 183: }
184:
185: /* If defined Username & Password */
186: if (csUser && *csUser) {
1.1.1.1.2.3! misho 187: user = (mqtthdr_var_t*) data;
1.1 misho 188: user->var_sb.val = htons(strlen(csUser));
189: memcpy(user->var_data, csUser, ntohs(user->var_sb.val));
1.1.1.1.2.3! misho 190: data += MQTTHDR_VAR_SIZEOF(user);
1.1 misho 191:
192: if (csPass && *csPass) {
1.1.1.1.2.3! misho 193: pass = (mqtthdr_var_t*) data;
1.1 misho 194: pass->var_sb.val = htons(strlen(csPass));
195: memcpy(pass->var_data, csPass, ntohs(pass->var_sb.val));
1.1.1.1.2.3! misho 196: data += MQTTHDR_VAR_SIZEOF(pass);
1.1 misho 197: }
198: }
199:
1.1.1.1.2.3! misho 200: return siz + len;
1.1 misho 201: }
202:
203: /*
204: * mqtt_msgCONNACK() Create CONNACK message
205: *
206: * @buf = Message buffer
207: * @retcode = Return code
208: * return: -1 error or >-1 message size for send
209: */
210: int
211: mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char retcode)
212: {
213: int siz = 0;
214: struct mqtthdr *hdr;
215: mqtthdr_connack_t *ack;
216:
217: if (!buf)
218: return -1;
219: if (retcode > MQTT_RETCODE_DENIED) {
1.1.1.1.2.1 misho 220: mqtt_SetErr(EINVAL, "Invalid retcode");
1.1 misho 221: return -1;
222: }
223:
224: if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t)) == -1)
225: return -1;
226: else {
227: hdr = (struct mqtthdr *) (buf->msg_base + siz);
228: siz += sizeof(struct mqtthdr);
229: ack = (mqtthdr_connack_t*) (buf->msg_base + siz);
230: siz += sizeof(mqtthdr_connack_t);
231: }
232:
233: /* fixed header */
234: MQTTHDR_MSGINIT(hdr);
235: hdr->mqtt_msg.type = MQTT_TYPE_CONNACK;
236: *hdr->mqtt_len = sizeof(mqtthdr_connack_t);
237:
238: /* CONNACK header */
239: ack->reserved = 0;
240: ack->retcode = retcode;
241:
242: return siz;
243: }
244:
245: static int
246: _mqtt_msgSIMPLE_(mqtt_msg_t * __restrict buf, u_char cmd)
247: {
248: int siz = 0;
249: struct mqtthdr *hdr;
250:
251: if (!buf)
252: return -1;
253:
254: if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr)) == -1)
255: return -1;
256: else {
257: hdr = (struct mqtthdr *) (buf->msg_base + siz);
258: siz += sizeof(struct mqtthdr);
259: }
260:
261: /* fixed header */
262: MQTTHDR_MSGINIT(hdr);
263: hdr->mqtt_msg.type = cmd;
264: *hdr->mqtt_len = 0;
265:
266: return siz;
267: }
268:
269: /*
270: * mqtt_msgPINGREQ() Create PINGREQ message
271: *
272: * @buf = Message buffer
273: * return: -1 error or >-1 message size for send
274: */
275: int
276: mqtt_msgPINGREQ(mqtt_msg_t * __restrict buf)
277: {
278: return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGREQ);
279: }
280:
281: /*
282: * mqtt_msgPINGRESP() Create PINGRESP message
283: *
284: * @buf = Message buffer
285: * return: -1 error or >-1 message size for send
286: */
287: int
288: mqtt_msgPINGRESP(mqtt_msg_t * __restrict buf)
289: {
290: return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGRESP);
291: }
292:
293: /*
294: * mqtt_msgDISCONNECT() Create DISCONNECT message
295: *
296: * @buf = Message buffer
297: * return: -1 error or >-1 message size for send
298: */
299: int
300: mqtt_msgDISCONNECT(mqtt_msg_t * __restrict buf)
301: {
302: return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_DISCONNECT);
303: }
304:
305: /* ============= decode ============ */
306:
307: /*
308: * mqtt_readCONNECT() Read elements from CONNECT message
309: *
310: * @buf = Message buffer
311: * @kasec = Keep Alive in seconds for current connection
312: * @psConnID = ConnectID
313: * @connLen = ConnectID length
314: * @psUser = Username if !=NULL
315: * @userLen = Username length
316: * @psPass = Password for Username, only if csUser is set
317: * @passLen = Password length
318: * @psWillTopic = Will Topic if !=NULL Will Flags set into message and must be free()
319: * @psWillMessage = Will Message, may be NULL if !NULL must be free() after use!
320: * return: .reserved == 1 is error or == 0 connection flags & msg ok
321: */
322: mqtthdr_connack_t
323: mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short *kasec, char * __restrict psConnID, int connLen,
324: char * __restrict psUser, int userLen, char * __restrict psPass, int passLen,
325: char ** __restrict psWillTopic, char ** __restrict psWillMessage)
326: {
327: mqtthdr_connflgs_t flg = { MQTT_CONNFLGS_INIT };
328: mqtthdr_connack_t cack = { 1, MQTT_RETCODE_DENIED };
329: struct mqtthdr *hdr;
330: mqtthdr_var_t *var;
331: mqtt_len_t *ka;
332: mqtthdr_protover_t *proto;
333: int len, ret;
334: caddr_t pos;
335:
336: if (!buf || !buf->msg_base || !buf->msg_len || !psConnID || !connLen)
337: return cack;
338:
339: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNECT, &ret, &len);
340: if (!hdr)
341: return cack;
342: if (len < 12) {
1.1.1.1.2.1 misho 343: mqtt_SetErr(EINVAL, "Short message length %d", len);
1.1 misho 344: return cack;
345: } else {
346: pos = buf->msg_base + ret + 1;
347: var = (mqtthdr_var_t*) pos;
348: }
349: /* check init string & protocol */
350: if (var->var_sb.sb.l != 6 || strncmp((char*) var->var_data, MQTT_CONN_STR, 6)) {
1.1.1.1.2.1 misho 351: mqtt_SetErr(EINVAL, "Invalid init string %.6s(%d)",
1.1 misho 352: var->var_data, var->var_sb.sb.l);
353: cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL;
354: return cack;
355: } else {
356: pos += var->var_sb.sb.l + sizeof(mqtt_len_t);
357: proto = (mqtthdr_protover_t*) pos;
358: }
359: if (*proto != MQTT_PROTO_VER) {
1.1.1.1.2.1 misho 360: mqtt_SetErr(EINVAL, "Invalid protocol version %d", *pos);
1.1 misho 361: cack.retcode = MQTT_RETCODE_REFUSE_VER;
362: return cack;
363: } else
364: pos++;
365: flg = *(mqtthdr_connflgs_t*) pos;
366: pos++;
367: ka = (mqtt_len_t*) pos;
368: *kasec = ntohs(ka->val);
369: pos += sizeof(mqtt_len_t);
370:
371: len -= pos - (caddr_t) var;
372:
373: /* get ConnID */
374: var = (mqtthdr_var_t*) pos;
375: len -= MQTTHDR_VAR_SIZEOF(var);
376: if (len < 0 || var->var_sb.sb.l > 23) {
1.1.1.1.2.1 misho 377: mqtt_SetErr(EINVAL, "Unexpected EOM at Connection ID %d", len);
1.1 misho 378: cack.retcode = MQTT_RETCODE_REFUSE_ID;
379: return cack;
380: } else {
381: memset(psConnID, 0, connLen--);
382: memcpy(psConnID, var->var_data, ntohs(var->var_sb.val) > connLen ? connLen : ntohs(var->var_sb.val));
383: pos += MQTTHDR_VAR_SIZEOF(var);
384: }
385:
386: /* get Willz */
387: if (flg.will_flg) {
388: var = (mqtthdr_var_t*) pos;
389: len -= MQTTHDR_VAR_SIZEOF(var);
390: if (len < 0) {
1.1.1.1.2.1 misho 391: mqtt_SetErr(EINVAL, "Unexpected EOM at Will Topic %d", len);
1.1 misho 392: cack.retcode = MQTT_RETCODE_REFUSE_ID;
393: return cack;
394: } else {
395: if (psWillTopic) {
396: *psWillTopic = malloc(ntohs(var->var_sb.val) + 1);
397: if (!*psWillTopic) {
398: LOGERR;
399: cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL;
400: return cack;
401: } else
402: memset(*psWillTopic, 0, ntohs(var->var_sb.val) + 1);
403: memcpy(*psWillTopic, var->var_data, ntohs(var->var_sb.val));
404: }
405: pos += MQTTHDR_VAR_SIZEOF(var);
406: }
407:
408: var = (mqtthdr_var_t*) pos;
409: len -= MQTTHDR_VAR_SIZEOF(var);
410: if (len < 0) {
1.1.1.1.2.1 misho 411: mqtt_SetErr(EINVAL, "Unexpected EOM at Will Message %d", len);
1.1 misho 412: cack.retcode = MQTT_RETCODE_REFUSE_ID;
413: return cack;
414: } else {
415: if (psWillMessage) {
416: *psWillMessage = malloc(ntohs(var->var_sb.val) + 1);
417: if (!*psWillMessage) {
418: LOGERR;
419: cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL;
420: return cack;
421: } else
422: memset(*psWillMessage, 0, ntohs(var->var_sb.val) + 1);
423: memcpy(*psWillMessage, var->var_data, ntohs(var->var_sb.val));
424: }
425: pos += MQTTHDR_VAR_SIZEOF(var);
426: }
427: }
428:
429: /* get User/Pass */
430: if (flg.username) {
431: var = (mqtthdr_var_t*) pos;
432: len -= MQTTHDR_VAR_SIZEOF(var);
433: if (len < 0 || var->var_sb.sb.l > 12) {
1.1.1.1.2.1 misho 434: mqtt_SetErr(EINVAL, "Unexpected EOM at Username %d", len);
1.1 misho 435: cack.retcode = MQTT_RETCODE_REFUSE_USERPASS;
436: return cack;
437: } else {
438: if (psUser && userLen) {
439: memset(psUser, 0, userLen--);
440: memcpy(psUser, var->var_data,
441: ntohs(var->var_sb.val) > userLen ? userLen : ntohs(var->var_sb.val));
442: }
443: pos += MQTTHDR_VAR_SIZEOF(var);
444: }
445: }
446: if (flg.password) {
447: var = (mqtthdr_var_t*) pos;
448: len -= MQTTHDR_VAR_SIZEOF(var);
449: if (len < 0 || var->var_sb.sb.l > 12) {
1.1.1.1.2.1 misho 450: mqtt_SetErr(EINVAL, "Unexpected EOM at Password %d", len);
1.1 misho 451: cack.retcode = MQTT_RETCODE_REFUSE_USERPASS;
452: return cack;
453: } else {
454: if (psPass && passLen) {
455: memset(psPass, 0, passLen--);
456: memcpy(psPass, var->var_data,
457: ntohs(var->var_sb.val) > passLen ? passLen : ntohs(var->var_sb.val));
458: }
459: pos += MQTTHDR_VAR_SIZEOF(var);
460: }
461: }
462:
463: flg.reserved = 0;
464: cack.reserved = flg.flags;
465: cack.retcode = MQTT_RETCODE_ACCEPTED;
466: return cack;
467: }
468:
469: /*
470: * mqtt_readCONNACK() Read CONNACK message
471: *
472: * @buf = Message buffer
473: * return: -1 error or >-1 CONNECT message return code
474: */
475: u_char
476: mqtt_readCONNACK(mqtt_msg_t * __restrict buf)
477: {
478: int len, ret;
479: struct mqtthdr *hdr;
480: mqtthdr_connack_t *ack;
481: caddr_t pos;
482:
483: if (!buf || !buf->msg_base || !buf->msg_len)
484: return (u_char) -1;
485:
486: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNACK, &ret, &len);
487: if (!hdr)
488: return (u_char) -1;
489: if (len < sizeof(mqtthdr_connack_t)) {
1.1.1.1.2.1 misho 490: mqtt_SetErr(EINVAL, "Short message length %d", len);
1.1 misho 491: return (u_char) -1;
492: } else {
493: pos = buf->msg_base + ret + 1;
494: ack = (mqtthdr_connack_t*) pos;
495: }
496:
497: if (ack->retcode > MQTT_RETCODE_DENIED) {
1.1.1.1.2.1 misho 498: mqtt_SetErr(EINVAL, "Invalid retcode %u", ack->retcode);
1.1 misho 499: return (u_char) -1;
500: }
501:
502: return ack->retcode;
503: }
504:
505: /*
506: * mqtt_readDISCONNECT() Read DISCONNECT message
507: *
508: * @buf = Message buffer
509: * return: -1 error, 0 ok, >0 undefined result
510: */
511: int
512: mqtt_readDISCONNECT(mqtt_msg_t * __restrict buf)
513: {
514: int len, ret;
515: struct mqtthdr *hdr;
516:
517: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_DISCONNECT, &ret, &len);
518: if (!hdr || ret != 1)
519: return -1;
520:
521: return len;
522: }
523:
524: /*
525: * mqtt_readPINGREQ() Read PINGREQ message
526: *
527: * @buf = Message buffer
528: * return: -1 error, 0 ok, >0 undefined result
529: */
530: int
531: mqtt_readPINGREQ(mqtt_msg_t * __restrict buf)
532: {
533: int len, ret;
534: struct mqtthdr *hdr;
535:
536: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGREQ, &ret, &len);
537: if (!hdr || ret != 1)
538: return -1;
539:
540: return len;
541: }
542:
543: /*
544: * mqtt_readPINGRESP() Read PINGRESP message
545: *
546: * @buf = Message buffer
547: * return: -1 error, 0 ok, >0 undefined result
548: */
549: int
550: mqtt_readPINGRESP(mqtt_msg_t * __restrict buf)
551: {
552: int len, ret;
553: struct mqtthdr *hdr;
554:
555: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGRESP, &ret, &len);
556: if (!hdr || ret != 1)
557: return -1;
558:
559: return len;
560: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>