Diff for /libaitmqtt/src/conn.c between versions 1.3 and 1.3.12.5

version 1.3, 2012/06/28 11:06:17 version 1.3.12.5, 2022/09/15 21:06:05
Line 12  terms: Line 12  terms:
 All of the documentation and software included in the ELWIX and AITNET  All of the documentation and software included in the ELWIX and AITNET
 Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>  Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   
Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012Copyright 2004 - 2022
         by Michael Pounov <misho@elwix.org>.  All rights reserved.          by Michael Pounov <misho@elwix.org>.  All rights reserved.
   
 Redistribution and use in source and binary forms, with or without  Redistribution and use in source and binary forms, with or without
Line 49  SUCH DAMAGE. Line 49  SUCH DAMAGE.
 /*  /*
  * mqtt_msgCONNECT() Create CONNECT message   * mqtt_msgCONNECT() Create CONNECT message
  *   *
  * @buf = Message buffer  
  * @csConnID = ConnectID   * @csConnID = ConnectID
 * @kasec = Keep alive timeout, if =0 default timeout for MQTT * @Version = MQTT version, if =0 default version is 3.1.1
  * @KASec = Keep alive timeout, if =0 default timeout for MQTT
  * @csUser = Username if !=NULL   * @csUser = Username if !=NULL
  * @csPass = Password for Username, only if csUser is set   * @csPass = Password for Username, only if csUser is set
  * @csWillTopic = Will Topic if !=NULL Will Flags set into message   * @csWillTopic = Will Topic if !=NULL Will Flags set into message
Line 59  SUCH DAMAGE. Line 59  SUCH DAMAGE.
  * @ClrSess = Clear Session subscriptions after disconnect   * @ClrSess = Clear Session subscriptions after disconnect
  * @WillQOS = Will QOS if csWillTopic is set   * @WillQOS = Will QOS if csWillTopic is set
  * @WillRetain = Will Retain Will Message if csWillTopic is set   * @WillRetain = Will Retain Will Message if csWillTopic is set
 * return: -1 error or >-1 message size for send * return: NULL error or allocated CONNECT message
  */   */
intmqtt_msg_t *
mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const char *csConnID, mqtt_msgCONNECT(const char *csConnID, u_char Version, u_short KASec, 
                u_short kasec, const char *csUser, const char *csPass,                 const char *csUser, const char *csPass, 
                 const char *csWillTopic, const char *csWillMessage,                   const char *csWillTopic, const char *csWillMessage, 
                 u_char ClrSess, u_char WillQOS, u_char WillRetain)                  u_char ClrSess, u_char WillQOS, u_char WillRetain)
 {  {
         int len, siz = 0;          int len, siz = 0;
         u_int n, *l;          u_int n, *l;
           mqtt_msg_t *msg = NULL;
         struct mqtthdr *hdr;          struct mqtthdr *hdr;
         mqtthdr_var_t *var, *cid, *topic, *wmsg, *user, *pass;          mqtthdr_var_t *var, *cid, *topic, *wmsg, *user, *pass;
         mqtthdr_protover_t *proto;  
         mqtthdr_connflgs_t *flags;          mqtthdr_connflgs_t *flags;
         mqtt_len_t *ka;          mqtt_len_t *ka;
         void *data;          void *data;
   
        if (!buf || !csConnID)        if (!csConnID)
                return -1;                return NULL;
        if (strlen(csConnID) > 23) {        if (strlen(csConnID) >= MQTT_CONNID_MAX) {
                mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max 23 bytes)");                mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max %d bytes)"
                return -1;                                MQTT_CONNID_MAX - 1);
                 return NULL;
         }          }
        if (csUser && strlen(csUser) > 12) {        if (Version && (Version < MQTT_PROTO_VER_3 || Version > MQTT_PROTO_VER_5)) {
                mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max 12 bytes)");                mqtt_SetErr(EINVAL, "Unsupported version");
                return -1;                return NULL;
         }          }
        if (csPass && strlen(csPass) > 12) {        if (csUser && strlen(csUser) >= MQTT_CRED_MAX) {
                mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max 12 bytes)");                mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max %d bytes)"
                return -1;                                MQTT_CRED_MAX - 1);
                 return NULL;
         }          }
           if (csPass && strlen(csPass) >= MQTT_CRED_MAX) {
                   mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max %d bytes)", 
                                   MQTT_CRED_MAX - 1);
                   return NULL;
           }
         if (WillQOS > MQTT_QOS_EXACTLY) {          if (WillQOS > MQTT_QOS_EXACTLY) {
                 mqtt_SetErr(EINVAL, "Invalid argument WillQOS - unknown QOS value");                  mqtt_SetErr(EINVAL, "Invalid argument WillQOS - unknown QOS value");
                return -1;                return NULL;
         }          }
   
         /* calculate message size */          /* calculate message size */
        len = 10 + sizeof(mqtt_len_t);                   /* connect arguments */        len = 10;        /* connect arguments: MQTT(6)+Version(1)+ConnFlags(1)+KeepAlive(2) */
         len += sizeof(mqtt_len_t) + strlen(csConnID);   /* connect id */          len += sizeof(mqtt_len_t) + strlen(csConnID);   /* connect id */
         if (csUser && *csUser) {                        /* user/pass */          if (csUser && *csUser) {                        /* user/pass */
                 len += sizeof(mqtt_len_t) + strlen(csUser);                  len += sizeof(mqtt_len_t) + strlen(csUser);
Line 113  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha Line 120  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha
         n = mqtt_encodeLen(len);                        /* message size */          n = mqtt_encodeLen(len);                        /* message size */
         siz += mqtt_sizeLen(n) - 1;                     /* length size */          siz += mqtt_sizeLen(n) - 1;                     /* length size */
   
        if (mqtt_msgRealloc(buf, siz + len) == -1)        if (!(msg = mqtt_msgAlloc(siz + len)))
                return -1;                return NULL;
         else {          else {
                data = buf->msg_base;                data = msg->msg_base;
                 hdr = (struct mqtthdr *) data;                  hdr = (struct mqtthdr *) data;
         }          }
   
         /* fixed header */          /* fixed header */
         MQTTHDR_MSGINIT(hdr);  
         hdr->mqtt_msg.type = MQTT_TYPE_CONNECT;          hdr->mqtt_msg.type = MQTT_TYPE_CONNECT;
         l = (u_int*) hdr->mqtt_len;          l = (u_int*) hdr->mqtt_len;
         *l = n;          *l = n;
Line 129  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha Line 135  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha
   
         /* variable header */          /* variable header */
         var = (mqtthdr_var_t*) data;          var = (mqtthdr_var_t*) data;
        var->var_sb.val = htons(strlen(MQTT_CONN_STR));        var->var_sb.val = htons(strlen(MQTT_PROTO_STR));
        memcpy(var->var_data, MQTT_CONN_STR, ntohs(var->var_sb.val));        memcpy(var->var_data, MQTT_PROTO_STR, ntohs(var->var_sb.val));
         data += MQTTHDR_VAR_SIZEOF(var);          data += MQTTHDR_VAR_SIZEOF(var);
   
         /* protocol version */          /* protocol version */
        proto = (mqtthdr_protover_t*) data++;        *(u_char*) data++ = Version ? Version : MQTT_PROTO_VER_311;
        *proto = MQTT_PROTO_VER; 
   
         /* CONNECT header */          /* CONNECT header */
         flags = (mqtthdr_connflgs_t*) data++;          flags = (mqtthdr_connflgs_t*) data++;
Line 159  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha Line 164  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha
   
         /* keep alive */          /* keep alive */
         ka = (mqtt_len_t*) data;          ka = (mqtt_len_t*) data;
        ka->val = kasec ? htons(kasec) : htons(MQTT_KEEPALIVE);        ka->val = KASec ? htons(KASec) : htons(MQTT_KEEPALIVE);
         data += sizeof(mqtt_len_t);          data += sizeof(mqtt_len_t);
   
         /* ConnID */          /* ConnID */
Line 199  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha Line 204  mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha
                 }                  }
         }          }
   
        return siz + len;        return msg;
 }  }
   
 /*  /*
  * mqtt_msgCONNACK() Create CONNACK message   * mqtt_msgCONNACK() Create CONNACK message
  *   *
  * @buf = Message buffer  
  * @retcode = Return code   * @retcode = Return code
 * return: -1 error or >-1 message size for send * return: NULL error or allocated CONNACK message
  */   */
intmqtt_msg_t *
mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char retcode)mqtt_msgCONNACK(u_char retcode)
 {  {
         int siz = 0;  
         struct mqtthdr *hdr;          struct mqtthdr *hdr;
         mqtthdr_connack_t *ack;          mqtthdr_connack_t *ack;
           mqtt_msg_t *msg = NULL;
   
         if (!buf)  
                 return -1;  
         if (retcode > MQTT_RETCODE_DENIED) {          if (retcode > MQTT_RETCODE_DENIED) {
                 mqtt_SetErr(EINVAL, "Invalid retcode");                  mqtt_SetErr(EINVAL, "Invalid retcode");
                return -1;                return NULL;
         }          }
   
        if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t)) == -1)        if (!(msg = mqtt_msgAlloc(sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t))))
                return -1;                return NULL;
         else {          else {
                hdr = (struct mqtthdr *) (buf->msg_base + siz);                hdr = (struct mqtthdr *) msg->msg_base;
                siz += sizeof(struct mqtthdr);                ack = (mqtthdr_connack_t*) (msg->msg_base + sizeof(struct mqtthdr));
                ack = (mqtthdr_connack_t*) (buf->msg_base + siz); 
                siz += sizeof(mqtthdr_connack_t); 
         }          }
   
         /* fixed header */          /* fixed header */
         MQTTHDR_MSGINIT(hdr);  
         hdr->mqtt_msg.type = MQTT_TYPE_CONNACK;          hdr->mqtt_msg.type = MQTT_TYPE_CONNACK;
         *hdr->mqtt_len = sizeof(mqtthdr_connack_t);          *hdr->mqtt_len = sizeof(mqtthdr_connack_t);
   
Line 241  mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char re Line 240  mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char re
         ack->reserved = 0;          ack->reserved = 0;
         ack->retcode = retcode;          ack->retcode = retcode;
   
        return siz;        return msg;
 }  }
   
static intstatic mqtt_msg_t *
_mqtt_msgSIMPLE_(mqtt_msg_t * __restrict buf, u_char cmd)_mqtt_msgSIMPLE_(u_char cmd)
 {  {
         int siz = 0;  
         struct mqtthdr *hdr;          struct mqtthdr *hdr;
           mqtt_msg_t *msg = NULL;
   
        if (!buf)        if (!(msg = mqtt_msgAlloc(sizeof(struct mqtthdr))))
                return -1;                return NULL;
         else
                 hdr = (struct mqtthdr *) msg->msg_base;
   
         if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr)) == -1)  
                 return -1;  
         else {  
                 hdr = (struct mqtthdr *) (buf->msg_base + siz);  
                 siz += sizeof(struct mqtthdr);  
         }  
   
         /* fixed header */          /* fixed header */
         MQTTHDR_MSGINIT(hdr);  
         hdr->mqtt_msg.type = cmd;          hdr->mqtt_msg.type = cmd;
         *hdr->mqtt_len = 0;          *hdr->mqtt_len = 0;
   
        return siz;        return msg;
 }  }
   
 /*  /*
  * mqtt_msgPINGREQ() Create PINGREQ message   * mqtt_msgPINGREQ() Create PINGREQ message
  *   *
 * @buf = Message buffer * return: NULL error or allocated message
 * return: -1 error or >-1 message size for send 
  */   */
intmqtt_msg_t *
mqtt_msgPINGREQ(mqtt_msg_t * __restrict buf)mqtt_msgPINGREQ()
 {  {
        return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGREQ);        return _mqtt_msgSIMPLE_(MQTT_TYPE_PINGREQ);
 }  }
   
 /*  /*
  * mqtt_msgPINGRESP() Create PINGRESP message   * mqtt_msgPINGRESP() Create PINGRESP message
  *   *
 * @buf = Message buffer * return: NULL error or allocated message
 * return: -1 error or >-1 message size for send 
  */   */
intmqtt_msg_t *
mqtt_msgPINGRESP(mqtt_msg_t * __restrict buf)mqtt_msgPINGRESP()
 {  {
        return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGRESP);        return _mqtt_msgSIMPLE_(MQTT_TYPE_PINGRESP);
 }  }
   
 /*  /*
  * mqtt_msgDISCONNECT() Create DISCONNECT message   * mqtt_msgDISCONNECT() Create DISCONNECT message
  *   *
 * @buf = Message buffer * return: NULL error or allocated message
 * return: -1 error or >-1 message size for send 
  */   */
intmqtt_msg_t *
mqtt_msgDISCONNECT(mqtt_msg_t * __restrict buf)mqtt_msgDISCONNECT()
 {  {
        return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_DISCONNECT);        return _mqtt_msgSIMPLE_(MQTT_TYPE_DISCONNECT);
} 
 
/* ============= decode ============ */ 
 
/* 
 * mqtt_readCONNECT() Read elements from CONNECT message 
 * 
 * @buf = Message buffer 
 * @kasec = Keep Alive in seconds for current connection 
 * @psConnID = ConnectID 
 * @connLen = ConnectID length 
 * @psUser = Username if !=NULL 
 * @userLen = Username length 
 * @psPass = Password for Username, only if csUser is set 
 * @passLen = Password length 
 * @psWillTopic = Will Topic if !=NULL Will Flags set into message and must be free() 
 * @psWillMessage = Will Message, may be NULL if !NULL must be free() after use! 
 * return: .reserved == 1 is error or == 0 connection flags & msg ok 
 */ 
mqtthdr_connack_t 
mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short *kasec, char * __restrict psConnID, int connLen,  
                char * __restrict psUser, int userLen, char * __restrict psPass, int passLen,   
                char ** __restrict psWillTopic, char ** __restrict psWillMessage) 
{ 
        mqtthdr_connflgs_t flg = { MQTT_CONNFLGS_INIT }; 
        mqtthdr_connack_t cack = { 1, MQTT_RETCODE_DENIED }; 
        struct mqtthdr *hdr; 
        mqtthdr_var_t *var; 
        mqtt_len_t *ka; 
        mqtthdr_protover_t *proto; 
        int len, ret; 
        caddr_t pos; 
 
        if (!buf || !buf->msg_base || !buf->msg_len || !psConnID || !connLen) 
                return cack; 
 
        hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNECT, &ret, &len); 
        if (!hdr) 
                return cack; 
        if (len < 12) { 
                mqtt_SetErr(EINVAL, "Short message length %d", len); 
                return cack; 
        } else { 
                pos = buf->msg_base + ret + 1; 
                var = (mqtthdr_var_t*) pos; 
        } 
        /* check init string & protocol */ 
        if (var->var_sb.sb.l != 6 || strncmp((char*) var->var_data, MQTT_CONN_STR, 6)) { 
                mqtt_SetErr(EINVAL, "Invalid init string %.6s(%d)",  
                                var->var_data, var->var_sb.sb.l); 
                cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL; 
                return cack; 
        } else { 
                pos += var->var_sb.sb.l + sizeof(mqtt_len_t); 
                proto = (mqtthdr_protover_t*) pos; 
        } 
        if (*proto != MQTT_PROTO_VER) { 
                mqtt_SetErr(EINVAL, "Invalid protocol version %d", *pos); 
                cack.retcode = MQTT_RETCODE_REFUSE_VER; 
                return cack; 
        } else 
                pos++; 
        flg = *(mqtthdr_connflgs_t*) pos; 
        pos++; 
        ka = (mqtt_len_t*) pos; 
        *kasec = ntohs(ka->val); 
        pos += sizeof(mqtt_len_t); 
 
        len -= pos - (caddr_t) var; 
 
        /* get ConnID */ 
        var = (mqtthdr_var_t*) pos; 
        len -= MQTTHDR_VAR_SIZEOF(var); 
        if (len < 0 || var->var_sb.sb.l > 23) { 
                mqtt_SetErr(EINVAL, "Unexpected EOM at Connection ID %d", len); 
                cack.retcode = MQTT_RETCODE_REFUSE_ID; 
                return cack; 
        } else { 
                memset(psConnID, 0, connLen--); 
                memcpy(psConnID, var->var_data, ntohs(var->var_sb.val) > connLen ? connLen : ntohs(var->var_sb.val)); 
                pos += MQTTHDR_VAR_SIZEOF(var); 
        } 
 
        /* get Willz */ 
        if (flg.will_flg) { 
                var = (mqtthdr_var_t*) pos; 
                len -= MQTTHDR_VAR_SIZEOF(var); 
                if (len < 0) { 
                        mqtt_SetErr(EINVAL, "Unexpected EOM at Will Topic %d", len); 
                        cack.retcode = MQTT_RETCODE_REFUSE_ID; 
                        return cack; 
                } else { 
                        if (psWillTopic) { 
                                *psWillTopic = malloc(ntohs(var->var_sb.val) + 1); 
                                if (!*psWillTopic) { 
                                        LOGERR; 
                                        cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL; 
                                        return cack; 
                                } else 
                                        memset(*psWillTopic, 0, ntohs(var->var_sb.val) + 1); 
                                memcpy(*psWillTopic, var->var_data, ntohs(var->var_sb.val)); 
                        } 
                        pos += MQTTHDR_VAR_SIZEOF(var); 
                } 
 
                var = (mqtthdr_var_t*) pos; 
                len -= MQTTHDR_VAR_SIZEOF(var); 
                if (len < 0) { 
                        mqtt_SetErr(EINVAL, "Unexpected EOM at Will Message %d", len); 
                        cack.retcode = MQTT_RETCODE_REFUSE_ID; 
                        return cack; 
                } else { 
                        if (psWillMessage) { 
                                *psWillMessage = malloc(ntohs(var->var_sb.val) + 1); 
                                if (!*psWillMessage) { 
                                        LOGERR; 
                                        cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL; 
                                        return cack; 
                                } else 
                                        memset(*psWillMessage, 0, ntohs(var->var_sb.val) + 1); 
                                memcpy(*psWillMessage, var->var_data, ntohs(var->var_sb.val)); 
                        } 
                        pos += MQTTHDR_VAR_SIZEOF(var); 
                } 
        } 
 
        /* get User/Pass */ 
        if (flg.username) { 
                var = (mqtthdr_var_t*) pos; 
                len -= MQTTHDR_VAR_SIZEOF(var); 
                if (len < 0 || var->var_sb.sb.l > 12) { 
                        mqtt_SetErr(EINVAL, "Unexpected EOM at Username %d", len); 
                        cack.retcode = MQTT_RETCODE_REFUSE_USERPASS; 
                        return cack; 
                } else { 
                        if (psUser && userLen) { 
                                memset(psUser, 0, userLen--); 
                                memcpy(psUser, var->var_data,  
                                                ntohs(var->var_sb.val) > userLen ? userLen : ntohs(var->var_sb.val)); 
                        } 
                        pos += MQTTHDR_VAR_SIZEOF(var); 
                } 
        } 
        if (flg.password) { 
                var = (mqtthdr_var_t*) pos; 
                len -= MQTTHDR_VAR_SIZEOF(var); 
                if (len < 0 || var->var_sb.sb.l > 12) { 
                        mqtt_SetErr(EINVAL, "Unexpected EOM at Password %d", len); 
                        cack.retcode = MQTT_RETCODE_REFUSE_USERPASS; 
                        return cack; 
                } else { 
                        if (psPass && passLen) { 
                                memset(psPass, 0, passLen--); 
                                memcpy(psPass, var->var_data,  
                                                ntohs(var->var_sb.val) > passLen ? passLen : ntohs(var->var_sb.val)); 
                        } 
                        pos += MQTTHDR_VAR_SIZEOF(var); 
                } 
        } 
 
        flg.reserved = 0; 
        cack.reserved = flg.flags; 
        cack.retcode = MQTT_RETCODE_ACCEPTED; 
        return cack; 
} 
 
/* 
 * mqtt_readCONNACK() Read CONNACK message 
 * 
 * @buf = Message buffer 
 * return: -1 error or >-1 CONNECT message return code 
 */ 
u_char 
mqtt_readCONNACK(mqtt_msg_t * __restrict buf) 
{ 
        int len, ret; 
        struct mqtthdr *hdr; 
        mqtthdr_connack_t *ack; 
        caddr_t pos; 
 
        if (!buf || !buf->msg_base || !buf->msg_len) 
                return (u_char) -1; 
 
        hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNACK, &ret, &len); 
        if (!hdr) 
                return (u_char) -1; 
        if (len < sizeof(mqtthdr_connack_t)) { 
                mqtt_SetErr(EINVAL, "Short message length %d", len); 
                return (u_char) -1; 
        } else { 
                pos = buf->msg_base + ret + 1; 
                ack = (mqtthdr_connack_t*) pos; 
        } 
 
        if (ack->retcode > MQTT_RETCODE_DENIED) { 
                mqtt_SetErr(EINVAL, "Invalid retcode %u", ack->retcode); 
                return (u_char) -1; 
        } 
 
        return ack->retcode; 
} 
 
/* 
 * mqtt_readDISCONNECT() Read DISCONNECT message 
 * 
 * @buf = Message buffer 
 * return: -1 error, 0 ok, >0 undefined result 
 */ 
int 
mqtt_readDISCONNECT(mqtt_msg_t * __restrict buf) 
{ 
        int len, ret; 
        struct mqtthdr *hdr; 
 
        hdr = _mqtt_readHEADER(buf, MQTT_TYPE_DISCONNECT, &ret, &len); 
        if (!hdr || ret != 1) 
                return -1; 
 
        return len; 
} 
 
/* 
 * mqtt_readPINGREQ() Read PINGREQ message 
 * 
 * @buf = Message buffer 
 * return: -1 error, 0 ok, >0 undefined result 
 */ 
int 
mqtt_readPINGREQ(mqtt_msg_t * __restrict buf) 
{ 
        int len, ret; 
        struct mqtthdr *hdr; 
 
        hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGREQ, &ret, &len); 
        if (!hdr || ret != 1) 
                return -1; 
 
        return len; 
} 
 
/* 
 * mqtt_readPINGRESP() Read PINGRESP message 
 * 
 * @buf = Message buffer 
 * return: -1 error, 0 ok, >0 undefined result 
 */ 
int 
mqtt_readPINGRESP(mqtt_msg_t * __restrict buf) 
{ 
        int len, ret; 
        struct mqtthdr *hdr; 
 
        hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGRESP, &ret, &len); 
        if (!hdr || ret != 1) 
                return -1; 
 
        return len; 
 }  }

Removed from v.1.3  
changed lines
  Added in v.1.3.12.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>