Annotation of mqtt/src/daemon.c, revision 1.1.2.30
1.1.2.1 misho 1: #include "global.h"
1.1.2.16 misho 2: #include "rtlm.h"
1.1.2.24 misho 3: #include "utils.h"
1.1.2.11 misho 4: #include "mqttd.h"
1.1.2.1 misho 5:
6:
1.1.2.30! misho 7: static void *startSession(sched_task_t *task);
! 8:
! 9:
1.1.2.14 misho 10: static inline struct tagSession *
1.1.2.18 misho 11: initSession(int sock, ait_val_t * __restrict v)
1.1.2.14 misho 12: {
13: struct tagSession *sess = NULL;
14: const char *str;
15:
1.1.2.20 misho 16: ioTRACE(5);
1.1.2.15 misho 17:
1.1.2.18 misho 18: if (!v)
1.1.2.14 misho 19: return NULL;
20:
21: sess = malloc(sizeof(struct tagSession));
22: if (!sess) {
1.1.2.20 misho 23: ioDEBUG(3, "Error:: in malloc #%d - %s", errno, strerror(errno));
1.1.2.18 misho 24: io_freeVar(v);
1.1.2.14 misho 25: return NULL;
26: } else
27: memset(sess, 0, sizeof(struct tagSession));
28:
1.1.2.17 misho 29: str = (const char*) cfg_GetAttribute(&cfg, CFG("mqttd"), CFG("retry"));
1.1.2.14 misho 30: if (!str)
31: sess->sess_retry = DEFAULT_RETRY;
32: else
33: sess->sess_retry = strtol(str, NULL, 0);
34:
1.1.2.30! misho 35: sess->sess_buf = mqtt_msgAlloc(USHRT_MAX);
1.1.2.14 misho 36: if (!sess->sess_buf) {
1.1.2.20 misho 37: ioDEBUG(3, "Error:: in msgAlloc #%d - %s", mqtt_GetErrno(), mqtt_GetError());
1.1.2.14 misho 38: free(sess);
1.1.2.18 misho 39: io_freeVar(v);
1.1.2.14 misho 40: return NULL;
41: }
42:
1.1.2.15 misho 43: sess->sess_sock = sock;
1.1.2.19 misho 44: strlcpy(sess->sess_addr, (char*) AIT_GET_STR(v), sizeof sess->sess_addr);
1.1.2.18 misho 45: io_freeVar(v);
1.1.2.14 misho 46: return sess;
47: }
48:
49: static void
1.1.2.30! misho 50: finiSession(struct tagSession *sess, int preservSock)
1.1.2.14 misho 51: {
52: struct tagStore *store;
53:
1.1.2.20 misho 54: ioTRACE(5);
1.1.2.15 misho 55:
1.1.2.14 misho 56: if (!sess)
57: return;
58:
1.1.2.30! misho 59: if (call.FiniSessPUB)
! 60: call.FiniSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, "%");
! 61:
! 62: while ((store = SLIST_FIRST(&sess->sess_sndqueue))) {
! 63: SLIST_REMOVE_HEAD(&sess->sess_sndqueue, st_node);
! 64: free(store);
! 65: }
1.1.2.14 misho 66:
67: if (sess->sess_will.msg)
68: free(sess->sess_will.msg);
69: if (sess->sess_will.topic)
70: free(sess->sess_will.topic);
71:
1.1.2.30! misho 72: if (sess->sess_sock > STDERR_FILENO && !preservSock)
1.1.2.24 misho 73: srv_Close(sess->sess_sock);
1.1.2.14 misho 74:
75: mqtt_msgFree(&sess->sess_buf, 42);
76:
77: free(sess);
78: }
79:
1.1.2.24 misho 80: static void
81: stopSession(struct tagSession *sess)
1.1.2.15 misho 82: {
1.1.2.24 misho 83: mqtt_msg_t msg = { NULL, 0 };
84: int ret;
85:
1.1.2.26 misho 86: ioTRACE(4);
87:
88: assert(sess);
89:
1.1.2.24 misho 90: pthread_mutex_lock(&mtx_sess);
91: TAILQ_REMOVE(&Sessions, sess, sess_node);
92: pthread_mutex_unlock(&mtx_sess);
93:
94: ret = mqtt_msgDISCONNECT(&msg);
95: if ((ret = send(sess->sess_sock, msg.msg_base, ret, 0)) == -1)
96: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
97: else {
98: ioDEBUG(5, "Sended %d bytes for disconnect", ret);
99: free(msg.msg_base);
1.1.2.27 misho 100: memset(&msg, 0, sizeof msg);
1.1.2.18 misho 101: }
102:
1.1.2.24 misho 103: ioDEBUG(1, "Close socket=%d", sess->sess_sock);
1.1.2.30! misho 104: finiSession(sess, 0);
1.1.2.27 misho 105:
1.1.2.28 misho 106: call.LOG(logg, "Session %s stopped from %s for user %s.\n", sess->sess_cid,
1.1.2.27 misho 107: sess->sess_addr, sess->sess_user);
1.1.2.24 misho 108: }
109:
1.1.2.26 misho 110: static int
111: KASession(struct tagSession *sess)
112: {
1.1.2.30! misho 113: mqtt_msg_t msg = { NULL, 0 };
1.1.2.26 misho 114: int ret;
115: struct pollfd pfd;
116:
117: ioTRACE(4);
118:
119: assert(sess);
120:
121: /* ping request */
122: ret = mqtt_msgPINGREQ(&msg);
123: if ((ret = send(sess->sess_sock, msg.msg_base, ret, 0)) == -1) {
124: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
125: return -1;
126: } else {
127: ioDEBUG(5, "Sended %d bytes for ping request", ret);
128: free(msg.msg_base);
129: memset(&msg, 0, sizeof msg);
130: }
131:
132: pfd.fd = sess->sess_sock;
133: pfd.events = POLLIN | POLLPRI;
1.1.2.30! misho 134: if ((ret = poll(&pfd, 1, sess->sess_ka * 1000)) == -1 ||
1.1.2.28 misho 135: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
1.1.2.26 misho 136: ioDEBUG(3, "Error:: poll(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
137: return -1;
138: } else if (!ret) {
1.1.2.30! misho 139: ioDEBUG(5, "Warning:: Session is abandoned ... must be disconnect!");
1.1.2.26 misho 140: return 1;
141: }
142: /* receive & decode packet */
1.1.2.30! misho 143: if (recv(sess->sess_sock, sess->sess_buf->msg_base, sess->sess_buf->msg_len, 0) == -1) {
1.1.2.26 misho 144: ioDEBUG(3, "Error:: recv(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
145: return -1;
146: }
1.1.2.30! misho 147: if (mqtt_readPINGRESP(sess->sess_buf)) {
! 148: ioDEBUG(5, "Warning:: Session is broken, not hear ping response ... must be disconnect!");
1.1.2.26 misho 149: return 2;
150: }
151:
152: /* Keep Alive is OK! */
153: return 0;
154: }
155:
1.1.2.24 misho 156: static void *
157: thrSession(struct tagSession *sess)
158: {
1.1.2.30! misho 159: mqtt_msg_t msg = { NULL, 0 };
! 160: int ret, locKill = 42;
1.1.2.28 misho 161: struct pollfd pfd;
162: struct mqtthdr *hdr;
1.1.2.30! misho 163: ait_val_t *v;
! 164: struct tagStore *store;
1.1.2.18 misho 165:
1.1.2.28 misho 166: pthread_cleanup_push((void(*)(void*)) stopSession, sess);
1.1.2.20 misho 167: ioTRACE(2);
1.1.2.15 misho 168:
1.1.2.28 misho 169: pfd.fd = sess->sess_sock;
170: pfd.events = POLLIN | POLLPRI;
1.1.2.30! misho 171: while (!Kill && locKill) {
! 172: if ((ret = poll(&pfd, 1, sess->sess_ka * 1000)) == -1 ||
1.1.2.28 misho 173: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
174: ioDEBUG(3, "Error:: poll(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
175: break;
176: } else if (!ret && (ret = KASession(sess))) {
177: call.LOG(logg, "Session %s keep-alive missing from %s for user %s ...\n",
178: sess->sess_cid, sess->sess_addr, sess->sess_user);
179: break;
180: }
181: /* receive & decode packet */
1.1.2.30! misho 182: if ((ret = recv(sess->sess_sock, sess->sess_buf->msg_base, sess->sess_buf->msg_len, 0)) == -1) {
1.1.2.28 misho 183: ioDEBUG(3, "Error:: recv(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
184: break;
185: } else if (!ret) {
186: ioDEBUG(4, "Session %s EOF received.", sess->sess_cid);
187: break;
188: } else
1.1.2.30! misho 189: hdr = (struct mqtthdr*) sess->sess_buf->msg_base;
1.1.2.28 misho 190:
1.1.2.29 misho 191: /* dispatch message type */
1.1.2.28 misho 192: switch (hdr->mqtt_msg.type) {
1.1.2.30! misho 193: case MQTT_TYPE_CONNECT:
! 194: ioDEBUG(5, "Exec CONNECT session");
! 195: pthread_mutex_lock(&mtx_sess);
! 196: TAILQ_REMOVE(&Sessions, sess, sess_node);
! 197: pthread_mutex_unlock(&mtx_sess);
! 198:
! 199: if (call.FiniSessPUB)
! 200: call.FiniSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, "%");
! 201:
! 202: while ((store = SLIST_FIRST(&sess->sess_sndqueue))) {
! 203: SLIST_REMOVE_HEAD(&sess->sess_sndqueue, st_node);
! 204: free(store);
! 205: }
! 206:
! 207: if (sess->sess_will.msg)
! 208: free(sess->sess_will.msg);
! 209: if (sess->sess_will.topic)
! 210: free(sess->sess_will.topic);
! 211:
! 212: if ((v = io_allocVar())) {
! 213: AIT_SET_STR(v, sess->sess_addr);
! 214: if (!schedEvent(root, startSession, v, (u_long) sess->sess_sock, sess, ret))
! 215: io_freeVar(v);
! 216: } else
! 217: ioLIBERR(mqtt);
! 218:
! 219: locKill ^= locKill;
! 220: continue;
! 221: case MQTT_TYPE_DISCONNECT:
! 222: ioDEBUG(5, "Exec DISCONNECT session");
! 223: pthread_mutex_lock(&mtx_sess);
! 224: TAILQ_REMOVE(&Sessions, sess, sess_node);
! 225: pthread_mutex_unlock(&mtx_sess);
! 226:
! 227: finiSession(sess, 0);
! 228: locKill ^= locKill;
! 229: continue;
! 230: case MQTT_TYPE_PUBLISH:
! 231: ioDEBUG(5, "Work in progress ...");
! 232: break;
! 233: case MQTT_TYPE_PUBREL:
! 234: break;
! 235: case MQTT_TYPE_SUBSCRIBE:
! 236: break;
! 237: case MQTT_TYPE_UNSUBSCRIBE:
! 238: break;
! 239: case MQTT_TYPE_PINGREQ:
! 240: break;
1.1.2.28 misho 241: default:
242: ioDEBUG(5, "Error:: Session %s, wrong command %d - DISCARDED",
243: sess->sess_cid, hdr->mqtt_msg.type);
244: break;
245: }
246: }
247:
1.1.2.30! misho 248: pthread_cleanup_pop(locKill);
1.1.2.15 misho 249: pthread_exit(NULL);
250: }
251:
252: static void *
1.1.2.5 misho 253: startSession(sched_task_t *task)
1.1.2.4 misho 254: {
1.1.2.11 misho 255: u_char basebuf[USHRT_MAX];
1.1.2.18 misho 256: mqtt_msg_t msg = { NULL, 0 }, buf = { basebuf, sizeof basebuf };
1.1.2.10 misho 257: mqtthdr_connflgs_t flg;
1.1.2.13 misho 258: mqtthdr_connack_t cack;
1.1.2.24 misho 259: struct tagSession *s, *sess = NULL;
1.1.2.18 misho 260: int ret;
261: pthread_attr_t attr;
1.1.2.6 misho 262:
1.1.2.20 misho 263: ioTRACE(4);
1.1.2.6 misho 264:
1.1.2.26 misho 265: assert(task);
266:
1.1.2.30! misho 267: ioDEBUG(3, "task_Data=%p", TASK_DATA(task));
! 268: if (!TASK_DATA(task)) {
! 269: sess = initSession(TASK_FD(task), TASK_ARG(task));
! 270: if (!sess) {
! 271: io_freeVar(TASK_ARG(task));
! 272: close(TASK_FD(task));
! 273: return NULL;
! 274: }
1.1.2.6 misho 275:
1.1.2.30! misho 276: /* receive & decode packet */
! 277: if (recv(sess->sess_sock, buf.msg_base, buf.msg_len, 0) == -1) {
! 278: ioDEBUG(3, "Error:: recv(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
! 279: finiSession(sess, 0);
! 280: return NULL;
! 281: }
! 282: } else {
! 283: sess = TASK_DATA(task);
! 284: buf.msg_len = TASK_DATLEN(task) > sizeof basebuf ? sizeof basebuf : TASK_DATLEN(task);
! 285: ioDEBUG(3, "debug:: sock=%d s=%p sbuf=%p sbl=%d ret=%d\n", sess->sess_sock, sess->sess_buf, sess->sess_buf->msg_base, (int) sess->sess_buf->msg_len, (int) TASK_DATLEN(task));
! 286: memcpy(buf.msg_base, sess->sess_buf->msg_base, buf.msg_len);
1.1.2.9 misho 287: }
1.1.2.30! misho 288:
1.1.2.14 misho 289: cack = mqtt_readCONNECT(&buf, &sess->sess_ka, sess->sess_cid, sizeof sess->sess_cid,
1.1.2.12 misho 290: sess->sess_user, sizeof sess->sess_user, sess->sess_pass, sizeof sess->sess_pass,
1.1.2.13 misho 291: &sess->sess_will.topic, &sess->sess_will.msg);
1.1.2.18 misho 292: ret = cack.retcode;
1.1.2.14 misho 293: flg.flags = cack.reserved;
294: if (flg.reserved) {
1.1.2.20 misho 295: ioDEBUG(3, "Error:: in MQTT protocol #%d - %s", mqtt_GetErrno(), mqtt_GetError());
1.1.2.10 misho 296: goto end;
1.1.2.14 misho 297: } else {
298: sess->sess_clean = flg.clean_sess;
299: sess->sess_will.qos = flg.will_qos;
300: sess->sess_will.retain = flg.will_retain;
301: sess->sess_will.flag = flg.will_flg;
1.1.2.12 misho 302: }
1.1.2.6 misho 303:
1.1.2.8 misho 304: /* check online table for user */
1.1.2.18 misho 305: if (call.LoginACC(&cfg, acc, sess->sess_user, sess->sess_pass) < 1) {
1.1.2.20 misho 306: ioDEBUG(0, "Login:: DENIED for username %s and password %s",
1.1.2.16 misho 307: sess->sess_user, sess->sess_pass);
1.1.2.21 misho 308: ret = MQTT_RETCODE_DENIED;
1.1.2.16 misho 309: goto end;
1.1.2.21 misho 310: } else {
1.1.2.24 misho 311: ioDEBUG(1, "Login:: ALLOWED for username %s ...", sess->sess_user);
1.1.2.21 misho 312: ret = MQTT_RETCODE_ACCEPTED;
313: }
1.1.2.23 misho 314: if (call.FiniSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, "%") > 0) {
1.1.2.24 misho 315: ioDEBUG(2, "Old session %s should be disconnect!", sess->sess_cid);
316: TAILQ_FOREACH(s, &Sessions, sess_node)
317: if (!strcmp(s->sess_cid, sess->sess_cid)) {
1.1.2.25 misho 318: /* found stale session & disconnect it! */
1.1.2.24 misho 319: stopSession(s);
320: break;
321: }
1.1.2.23 misho 322: }
323: if (call.InitSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, sess->sess_addr,
324: sess->sess_will.flag, sess->sess_will.topic, sess->sess_will.msg,
325: sess->sess_will.qos, sess->sess_will.retain) == -1) {
326: ioDEBUG(0, "Session %s DENIED for username %s", sess->sess_cid, sess->sess_user);
327: ret = MQTT_RETCODE_DENIED;
328: goto end;
329: } else {
330: ioDEBUG(0, "Session %s from %s and username %s is started",
331: sess->sess_cid, sess->sess_addr, sess->sess_user);
332: ret = MQTT_RETCODE_ACCEPTED;
333: }
1.1.2.6 misho 334:
1.1.2.18 misho 335: ret = mqtt_msgCONNACK(&msg, ret);
336: if ((ret = send(sess->sess_sock, msg.msg_base, ret, 0)) == -1) {
1.1.2.20 misho 337: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
1.1.2.30! misho 338: finiSession(sess, 0);
1.1.2.18 misho 339: return NULL;
340: } else {
1.1.2.20 misho 341: ioDEBUG(5, "Sended %d bytes", ret);
1.1.2.19 misho 342: free(msg.msg_base);
1.1.2.27 misho 343: memset(&msg, 0, sizeof msg);
1.1.2.18 misho 344: }
345:
1.1.2.15 misho 346: /* Start session thread OK ... */
1.1.2.18 misho 347: pthread_attr_init(&attr);
348: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
349:
350: pthread_mutex_lock(&mtx_sess);
1.1.2.15 misho 351: TAILQ_INSERT_TAIL(&Sessions, sess, sess_node);
1.1.2.18 misho 352: pthread_create(&sess->sess_tid, &attr, (void*(*)(void*)) thrSession, sess);
353: pthread_mutex_unlock(&mtx_sess);
354:
1.1.2.30! misho 355: call.LOG(logg, "Session %s started from %s for user %s (timeout=%d) OK!\n", sess->sess_cid,
! 356: sess->sess_addr, sess->sess_user, sess->sess_ka);
1.1.2.18 misho 357:
358: pthread_attr_destroy(&attr);
1.1.2.15 misho 359: return NULL;
1.1.2.6 misho 360: end: /* close client connection */
1.1.2.18 misho 361: ret = mqtt_msgCONNACK(&msg, ret);
362: if ((ret = send(sess->sess_sock, msg.msg_base, ret, 0)) == -1) {
1.1.2.20 misho 363: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
1.1.2.18 misho 364: } else {
1.1.2.20 misho 365: ioDEBUG(5, "Sended %d bytes", ret);
1.1.2.19 misho 366: free(msg.msg_base);
1.1.2.27 misho 367: memset(&msg, 0, sizeof msg);
1.1.2.18 misho 368: }
369:
1.1.2.20 misho 370: ioDEBUG(1, "Close client %s with socket=%d", sess->sess_addr, sess->sess_sock);
1.1.2.30! misho 371: finiSession(sess, 0);
1.1.2.6 misho 372: return NULL;
1.1.2.4 misho 373: }
374:
375: /* ----------------------------------------------------------------------- */
376:
1.1.2.5 misho 377: static void *
378: thrSched(void *arg __unused)
379: {
1.1.2.18 misho 380: struct tagSession *sess;
1.1.2.5 misho 381:
1.1.2.20 misho 382: ioTRACE(1);
383:
384: schedRun(root, &Kill);
1.1.2.18 misho 385:
386: TAILQ_FOREACH(sess, &Sessions, sess_node)
387: if (sess->sess_tid)
388: pthread_cancel(sess->sess_tid);
1.1.2.30! misho 389: ioDEBUG(5, "EXIT from Scheduler thread !!!");
1.1.2.5 misho 390: pthread_exit(NULL);
391: }
392:
1.1.2.2 misho 393: int
1.1.2.3 misho 394: Run(int sock)
1.1.2.2 misho 395: {
1.1.2.4 misho 396: io_sockaddr_t sa;
397: socklen_t sslen = sizeof sa.ss;
398: int cli;
1.1.2.5 misho 399: pthread_t tid;
1.1.2.18 misho 400: ait_val_t *v;
1.1.2.23 misho 401: char str[STRSIZ];
1.1.2.4 misho 402:
1.1.2.20 misho 403: ioTRACE(1);
1.1.2.2 misho 404:
1.1.2.5 misho 405: if (pthread_create(&tid, NULL, thrSched, NULL)) {
1.1.2.30! misho 406: ioSYSERR(0);
1.1.2.5 misho 407: return -1;
408: } else
409: pthread_detach(tid);
1.1.2.20 misho 410: ioDEBUG(2, "Run scheduler management thread");
1.1.2.5 misho 411:
1.1.2.24 misho 412: if (listen(sock, SOMAXCONN) == -1) {
1.1.2.30! misho 413: ioSYSERR(0);
1.1.2.3 misho 414: return -1;
415: }
416:
1.1.2.4 misho 417: while (!Kill) {
418: if ((cli = accept(sock, &sa.sa, &sslen)) == -1) {
1.1.2.20 misho 419: if (!Kill)
420: continue;
1.1.2.30! misho 421: ioSYSERR(0);
1.1.2.20 misho 422: break;
1.1.2.18 misho 423: }
424: v = io_allocVar();
425: if (!v) {
426: ioLIBERR(mqtt);
427: break;
1.1.2.23 misho 428: } else {
429: memset(str, 0, sizeof str);
430: snprintf(str, sizeof str, "%s:%hu", io_n2addr(&sa, v), io_n2port(&sa));
431: AIT_SET_STR(v, str);
432: }
433: ioDEBUG(1, "Connected client with socket=%d from %s", cli, AIT_GET_STR(v));
1.1.2.4 misho 434:
1.1.2.30! misho 435: if (!schedRead(root, startSession, v, cli, NULL, 0)) {
1.1.2.18 misho 436: io_freeVar(v);
1.1.2.4 misho 437: close(cli);
1.1.2.20 misho 438: ioDEBUG(1, "Terminated client with socket=%d", cli);
1.1.2.4 misho 439: }
440: }
441:
1.1.2.2 misho 442: return 0;
443: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>