mosquitto/src/context.c

229 lines
6.1 KiB
C
Raw Normal View History

2014-05-07 22:27:00 +00:00
/*
Copyright (c) 2009-2015 Roger Light <roger@atchoo.org>
2014-05-07 22:27:00 +00:00
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
http://www.eclipse.org/legal/epl-v10.html
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
Contributors:
Roger Light - initial implementation and documentation.
*/
#include <assert.h>
2014-09-14 17:08:09 +00:00
#include <time.h>
2014-05-07 22:27:00 +00:00
2015-04-29 20:37:47 +00:00
#include "config.h"
2014-05-07 22:27:00 +00:00
2015-04-29 20:37:47 +00:00
#include "mosquitto_broker.h"
#include "memory_mosq.h"
2015-04-29 20:23:59 +00:00
#include "packet_mosq.h"
2015-04-29 20:37:47 +00:00
#include "time_mosq.h"
2014-05-07 22:27:00 +00:00
#include "uthash.h"
2015-05-16 14:24:24 +00:00
struct mosquitto *context__init(struct mosquitto_db *db, int sock)
2014-05-07 22:27:00 +00:00
{
struct mosquitto *context;
char address[1024];
context = mosquitto__calloc(1, sizeof(struct mosquitto));
2014-05-07 22:27:00 +00:00
if(!context) return NULL;
context->state = mosq_cs_new;
context->sock = sock;
context->last_msg_in = mosquitto_time();
context->last_msg_out = mosquitto_time();
context->keepalive = 60; /* Default to 60s */
context->clean_session = true;
context->disconnect_t = 0;
context->id = NULL;
context->last_mid = 0;
context->will = NULL;
context->username = NULL;
context->password = NULL;
context->listener = NULL;
context->acl_list = NULL;
/* is_bridge records whether this client is a bridge or not. This could be
* done by looking at context->bridge for bridges that we create ourself,
* but incoming bridges need some other way of being recorded. */
context->is_bridge = false;
context->in_packet.payload = NULL;
2015-05-16 13:16:40 +00:00
packet__cleanup(&context->in_packet);
2014-05-07 22:27:00 +00:00
context->out_packet = NULL;
context->current_out_packet = NULL;
context->address = NULL;
2014-10-26 21:17:08 +00:00
if((int)sock >= 0){
2015-05-16 17:43:06 +00:00
if(!net__socket_get_address(sock, address, 1024)){
context->address = mosquitto__strdup(address);
2014-05-07 22:27:00 +00:00
}
if(!context->address){
/* getpeername and inet_ntop failed and not a bridge */
mosquitto__free(context);
2014-05-07 22:27:00 +00:00
return NULL;
}
}
context->bridge = NULL;
context->msgs = NULL;
context->last_msg = NULL;
context->msg_count = 0;
context->msg_count12 = 0;
#ifdef WITH_TLS
context->ssl = NULL;
#endif
2014-10-26 21:17:08 +00:00
if((int)context->sock >= 0){
HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context);
}
2014-05-07 22:27:00 +00:00
return context;
}
/*
* This will result in any outgoing packets going unsent. If we're disconnected
* forcefully then it is usually an error condition and shouldn't be a problem,
* but it will mean that CONNACK messages will never get sent for bad protocol
* versions for example.
*/
2015-05-16 14:24:24 +00:00
void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool do_free)
2014-05-07 22:27:00 +00:00
{
struct mosquitto__packet *packet;
2014-05-07 22:27:00 +00:00
struct mosquitto_client_msg *msg, *next;
int i;
2014-05-07 22:27:00 +00:00
if(!context) return;
if(context->username){
mosquitto__free(context->username);
2014-05-07 22:27:00 +00:00
context->username = NULL;
}
if(context->password){
mosquitto__free(context->password);
2014-05-07 22:27:00 +00:00
context->password = NULL;
}
#ifdef WITH_BRIDGE
if(context->bridge){
for(i=0; i<db->bridge_count; i++){
if(db->bridges[i] == context){
db->bridges[i] = NULL;
2014-06-28 00:38:58 +00:00
}
}
if(context->bridge->local_clientid){
mosquitto__free(context->bridge->local_clientid);
2014-06-29 22:16:10 +00:00
context->bridge->local_clientid = NULL;
2014-06-28 00:38:58 +00:00
}
if(context->bridge->remote_username){
context->bridge->remote_username = NULL;
2014-05-07 22:27:00 +00:00
}
if(context->bridge->remote_password){
context->bridge->remote_password = NULL;
2014-05-07 22:27:00 +00:00
}
2014-06-28 00:38:58 +00:00
if(context->bridge->local_username){
context->bridge->local_username = NULL;
}
if(context->bridge->local_password){
context->bridge->local_password = NULL;
}
if(context->bridge->local_clientid){
context->bridge->local_clientid = NULL;
}
2014-05-07 22:27:00 +00:00
}
#endif
mosquitto__socket_close(db, context);
2014-07-08 22:07:19 +00:00
if((do_free || context->clean_session) && db){
mqtt3_subs_clean_session(db, context);
2015-05-16 14:24:24 +00:00
db__messages_delete(db, context);
2014-05-07 22:27:00 +00:00
}
if(context->address){
mosquitto__free(context->address);
2014-05-07 22:27:00 +00:00
context->address = NULL;
}
2014-06-29 22:16:10 +00:00
2014-05-07 22:27:00 +00:00
if(context->id){
assert(db); /* db can only be NULL here if the client hasn't sent a
CONNECT and hence wouldn't have an id. */
HASH_DELETE(hh_id, db->contexts_by_id, context);
mosquitto__free(context->id);
2014-05-07 22:27:00 +00:00
context->id = NULL;
}
2015-05-16 13:16:40 +00:00
packet__cleanup(&(context->in_packet));
if(context->current_out_packet){
2015-05-16 13:16:40 +00:00
packet__cleanup(context->current_out_packet);
mosquitto__free(context->current_out_packet);
context->current_out_packet = NULL;
}
2014-05-07 22:27:00 +00:00
while(context->out_packet){
2015-05-16 13:16:40 +00:00
packet__cleanup(context->out_packet);
2014-05-07 22:27:00 +00:00
packet = context->out_packet;
context->out_packet = context->out_packet->next;
mosquitto__free(packet);
2014-05-07 22:27:00 +00:00
}
if(context->will){
if(context->will->topic) mosquitto__free(context->will->topic);
if(context->will->payload) mosquitto__free(context->will->payload);
mosquitto__free(context->will);
2014-05-07 22:27:00 +00:00
context->will = NULL;
}
if(do_free || context->clean_session){
msg = context->msgs;
while(msg){
next = msg->next;
2015-05-16 14:24:24 +00:00
db__msg_store_deref(db, &msg->store);
mosquitto__free(msg);
2014-05-07 22:27:00 +00:00
msg = next;
}
context->msgs = NULL;
context->last_msg = NULL;
}
if(do_free){
mosquitto__free(context);
2014-05-07 22:27:00 +00:00
}
}
2015-05-16 14:24:24 +00:00
void context__disconnect(struct mosquitto_db *db, struct mosquitto *ctxt)
2014-05-07 22:27:00 +00:00
{
if(ctxt->state != mosq_cs_disconnecting && ctxt->will){
/* Unexpected disconnect, queue the client will. */
2015-05-16 14:24:24 +00:00
db__messages_easy_queue(db, ctxt, ctxt->will->topic, ctxt->will->qos, ctxt->will->payloadlen, ctxt->will->payload, ctxt->will->retain);
2014-05-07 22:27:00 +00:00
}
if(ctxt->will){
if(ctxt->will->topic) mosquitto__free(ctxt->will->topic);
if(ctxt->will->payload) mosquitto__free(ctxt->will->payload);
mosquitto__free(ctxt->will);
2014-05-07 22:27:00 +00:00
ctxt->will = NULL;
}
ctxt->disconnect_t = time(NULL);
mosquitto__socket_close(db, ctxt);
2014-05-07 22:27:00 +00:00
}
2015-05-16 14:24:24 +00:00
void context__add_to_disused(struct mosquitto_db *db, struct mosquitto *context)
{
if(db->ll_for_free){
context->for_free_next = db->ll_for_free;
db->ll_for_free = context;
}else{
db->ll_for_free = context;
}
}
2015-05-16 14:24:24 +00:00
void context__free_disused(struct mosquitto_db *db)
{
struct mosquitto *context, *next;
2014-10-24 20:57:33 +00:00
assert(db);
context = db->ll_for_free;
while(context){
next = context->for_free_next;
2015-05-16 14:24:24 +00:00
context__cleanup(db, context, true);
context = next;
}
2014-09-22 22:37:19 +00:00
db->ll_for_free = NULL;
}