Annotation of mqtt/src/daemon.c, revision 1.2.2.11
1.2 misho 1: #include "global.h"
2: #include "rtlm.h"
3: #include "utils.h"
4: #include "mqttd.h"
5: #include "mqttd_calls.h"
6:
7:
8: static void *startSession(sched_task_t *task);
1.2.2.10 misho 9: static pthread_attr_t attr;
1.2 misho 10:
11:
12: static inline struct tagSession *
13: initSession(int sock, ait_val_t * __restrict v)
14: {
15: struct tagSession *sess = NULL;
16: const char *str;
17:
18: ioTRACE(5);
19:
20: if (!v)
21: return NULL;
22:
23: sess = malloc(sizeof(struct tagSession));
24: if (!sess) {
1.2.2.9 misho 25: ioSYSERR(0);
1.2 misho 26: io_freeVar(v);
27: return NULL;
28: } else
29: memset(sess, 0, sizeof(struct tagSession));
30:
1.2.2.4 misho 31: pthread_mutex_init(&sess->sess_mtx, NULL);
32:
1.2.2.9 misho 33: SLIST_INIT(&sess->sess_subscr);
1.2 misho 34:
1.2.2.5 misho 35: str = cfg_getAttribute(&cfg, "mqttd", "retry");
1.2 misho 36: if (!str)
37: sess->sess_retry = DEFAULT_RETRY;
38: else
39: sess->sess_retry = strtol(str, NULL, 0);
40:
1.2.2.9 misho 41: if (!(sess->sess_root = schedBegin())) {
42: ioLIBERR(sched);
43: free(sess);
44: io_freeVar(v);
45: return NULL;
46: }
47:
1.2 misho 48: sess->sess_buf = mqtt_msgAlloc(USHRT_MAX);
49: if (!sess->sess_buf) {
1.2.2.9 misho 50: ioLIBERR(mqtt);
51: schedEnd(&sess->sess_root);
1.2 misho 52: free(sess);
53: io_freeVar(v);
54: return NULL;
55: }
56:
1.2.2.8 misho 57: /* init server actor */
1.2.2.2 misho 58: sess->sess_srv = mqtt_srv_Init(sock, sess->sess_buf);
59: if (!sess->sess_srv) {
60: ioDEBUG(3, "Error:: in srv_Init #%d - %s", mqtt_GetErrno(), mqtt_GetError());
61: mqtt_msgFree(&sess->sess_buf, 42);
1.2.2.9 misho 62: schedEnd(&sess->sess_root);
1.2.2.2 misho 63: free(sess);
64: io_freeVar(v);
65: return NULL;
1.2.2.3 misho 66: } else {
67: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_CONNECT, cmdCONNECT);
68: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_PUBLISH, cmdPUBLISH);
69: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_PUBREL, cmdPUBREL);
70: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_SUBSCRIBE, cmdSUBSCRIBE);
71: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_UNSUBSCRIBE, cmdUNSUBSCRIBE);
72: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_PINGREQ, cmdPINGREQ);
73: mqtt_srv_setCmd(sess->sess_srv, MQTT_TYPE_DISCONNECT, cmdDISCONNECT);
1.2.2.2 misho 74: }
75:
1.2 misho 76: sess->sess_sock = sock;
77: strlcpy(sess->sess_addr, (char*) AIT_GET_STR(v), sizeof sess->sess_addr);
78: io_freeVar(v);
79: return sess;
80: }
81:
82: static void
1.2.2.9 misho 83: finiSession(struct tagSession *sess)
1.2 misho 84: {
85: struct tagStore *store;
86:
87: ioTRACE(5);
88:
89: if (!sess)
90: return;
91:
92: if (call.FiniSessPUB)
93: call.FiniSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, "%");
94:
1.2.2.6 misho 95: SESS_ELEM_LOCK(sess);
1.2 misho 96:
1.2.2.9 misho 97: while ((store = SLIST_FIRST(&sess->sess_subscr))) {
98: SLIST_REMOVE_HEAD(&sess->sess_subscr, st_node);
99:
100: if (store->st_subscr.sub_topic.msg_base)
101: free(store->st_subscr.sub_topic.msg_base);
102: if (store->st_subscr.sub_value.msg_base)
103: free(store->st_subscr.sub_value.msg_base);
104:
105: free(store);
106: }
1.2.2.6 misho 107: SESS_ELEM_UNLOCK(sess);
1.2.2.4 misho 108: pthread_mutex_destroy(&sess->sess_mtx);
1.2 misho 109:
1.2.2.9 misho 110: schedEnd(&sess->sess_root);
111:
1.2 misho 112: if (sess->sess_will.msg)
113: free(sess->sess_will.msg);
114: if (sess->sess_will.topic)
115: free(sess->sess_will.topic);
116:
1.2.2.9 misho 117: if (sess->sess_sock > STDERR_FILENO)
1.2 misho 118: srv_Close(sess->sess_sock);
119:
1.2.2.2 misho 120: mqtt_srv_Fini(&sess->sess_srv);
1.2 misho 121: mqtt_msgFree(&sess->sess_buf, 42);
122:
123: free(sess);
124: }
125:
126: static void
127: stopSession(struct tagSession *sess)
128: {
129: mqtt_msg_t msg = { NULL, 0 };
130: int ret;
131:
132: ioTRACE(4);
133:
134: assert(sess);
135:
1.2.2.6 misho 136: SESS_LOCK;
1.2 misho 137: TAILQ_REMOVE(&Sessions, sess, sess_node);
1.2.2.6 misho 138: SESS_UNLOCK;
1.2 misho 139:
140: ret = mqtt_msgDISCONNECT(&msg);
1.2.2.9 misho 141: send(sess->sess_sock, msg.msg_base, ret, MSG_NOSIGNAL);
142: free(msg.msg_base);
1.2 misho 143:
144: ioDEBUG(1, "Close socket=%d", sess->sess_sock);
1.2.2.9 misho 145: finiSession(sess);
1.2 misho 146:
147: call.LOG(logg, "Session %s stopped from %s for user %s.\n", sess->sess_cid,
148: sess->sess_addr, sess->sess_user);
149: }
150:
151: static int
152: KASession(struct tagSession *sess)
153: {
154: mqtt_msg_t msg = { NULL, 0 };
155: int ret;
156: struct pollfd pfd;
157:
158: ioTRACE(4);
159:
160: assert(sess);
161:
162: /* ping request */
163: ret = mqtt_msgPINGREQ(&msg);
1.2.2.9 misho 164: if ((ret = send(sess->sess_sock, msg.msg_base, ret, MSG_NOSIGNAL)) == -1) {
1.2 misho 165: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
166: return -1;
167: } else {
168: ioDEBUG(5, "Sended %d bytes for ping request", ret);
169: free(msg.msg_base);
170: memset(&msg, 0, sizeof msg);
171: }
172:
173: pfd.fd = sess->sess_sock;
174: pfd.events = POLLIN | POLLPRI;
175: if ((ret = poll(&pfd, 1, sess->sess_ka * 1000)) == -1 ||
176: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
177: ioDEBUG(3, "Error:: poll(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
178: return -1;
179: } else if (!ret) {
180: ioDEBUG(5, "Warning:: Session is abandoned ... must be disconnect!");
181: return 1;
182: }
183: /* receive & decode packet */
184: if (recv(sess->sess_sock, sess->sess_buf->msg_base, sess->sess_buf->msg_len, 0) == -1) {
185: ioDEBUG(3, "Error:: recv(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
186: return -1;
187: }
188: if (mqtt_readPINGRESP(sess->sess_buf)) {
189: ioDEBUG(5, "Warning:: Session is broken, not hear ping response ... must be disconnect!");
190: return 2;
191: }
192:
193: /* Keep Alive is OK! */
194: return 0;
195: }
196:
197: static void *
198: thrSession(struct tagSession *sess)
199: {
200: int ret, locKill = 42;
201: struct pollfd pfd;
202: struct mqtthdr *hdr;
203: ait_val_t *v;
204:
205: pthread_cleanup_push((void(*)(void*)) stopSession, sess);
206: ioTRACE(2);
207:
208: pfd.fd = sess->sess_sock;
209: pfd.events = POLLIN | POLLPRI;
210: while (!Kill && locKill) {
211: if ((ret = poll(&pfd, 1, sess->sess_ka * 1000)) == -1 ||
212: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
213: ioDEBUG(3, "Error:: poll(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
214: break;
215: } else if (!ret && (ret = KASession(sess))) {
216: call.LOG(logg, "Session %s keep-alive missing from %s for user %s ...\n",
217: sess->sess_cid, sess->sess_addr, sess->sess_user);
218: break;
219: }
220: /* receive & decode packet */
221: if ((ret = recv(sess->sess_sock, sess->sess_buf->msg_base, sess->sess_buf->msg_len, 0)) == -1) {
222: ioDEBUG(3, "Error:: recv(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
223: break;
224: } else if (!ret) {
225: ioDEBUG(4, "Session %s EOF received.", sess->sess_cid);
226: break;
227: } else
228: hdr = (struct mqtthdr*) sess->sess_buf->msg_base;
229:
230: /* dispatch message type */
1.2.2.3 misho 231: if (mqtt_srv_Dispatch(sess->sess_srv, sess))
232: ioLIBERR(mqtt);
1.2.2.11! misho 233: locKill ^= locKill;
1.2 misho 234: switch (hdr->mqtt_msg.type) {
235: case MQTT_TYPE_CONNECT:
236: ioDEBUG(5, "Exec CONNECT session");
237: if ((v = io_allocVar())) {
238: AIT_SET_STR(v, sess->sess_addr);
239: if (!schedEvent(root, startSession, v, (u_long) sess->sess_sock, sess, ret))
240: io_freeVar(v);
241: } else
242: ioLIBERR(mqtt);
243: continue;
244: case MQTT_TYPE_DISCONNECT:
245: ioDEBUG(5, "Exec DISCONNECT session");
1.2.2.9 misho 246: finiSession(sess);
1.2.2.11! misho 247: locKill = 42;
1.2 misho 248: continue;
249: case MQTT_TYPE_PUBLISH:
250: ioDEBUG(5, "Exec PUBLISH topic QoS=%d", hdr->mqtt_msg.qos);
1.2.2.3 misho 251: /*
252: if (cmdPUBLISH(sess))
1.2 misho 253: locKill ^= locKill;
1.2.2.3 misho 254: */
1.2 misho 255: break;
256: case MQTT_TYPE_PUBREL:
257: break;
258: case MQTT_TYPE_SUBSCRIBE:
259: break;
260: case MQTT_TYPE_UNSUBSCRIBE:
261: break;
262: case MQTT_TYPE_PINGREQ:
1.2.2.4 misho 263: ioDEBUG(5, "Exec PINGREQ session");
1.2 misho 264: break;
1.2.2.11! misho 265: case MQTT_TYPE_PINGRESP:
! 266: ioDEBUG(5, "Exec PINGRESP session");
! 267: break;
1.2 misho 268: default:
269: ioDEBUG(5, "Error:: Session %s, wrong command %d - DISCARDED",
270: sess->sess_cid, hdr->mqtt_msg.type);
271: break;
272: }
273: }
274:
275: pthread_cleanup_pop(locKill);
276: pthread_exit(NULL);
1.2.2.11! misho 277: return NULL;
1.2 misho 278: }
279:
280: static void *
281: startSession(sched_task_t *task)
282: {
283: u_char basebuf[USHRT_MAX];
284: mqtt_msg_t msg = { NULL, 0 }, buf = { basebuf, sizeof basebuf };
285: mqtthdr_connflgs_t flg;
286: mqtthdr_connack_t cack;
287: struct tagSession *s, *sess = NULL;
288: int ret;
289:
290: ioTRACE(4);
291:
292: assert(task);
1.2.2.11! misho 293: printf("aaaaaaaaaaaaaaaaa\n");
! 294: fflush(stdout);
1.2 misho 295:
296: if (!TASK_DATA(task)) {
1.2.2.8 misho 297: /* flow from accept new clients */
1.2 misho 298: sess = initSession(TASK_FD(task), TASK_ARG(task));
299: if (!sess) {
300: io_freeVar(TASK_ARG(task));
301: close(TASK_FD(task));
302: return NULL;
303: }
304:
305: /* receive & decode packet */
306: if (recv(sess->sess_sock, buf.msg_base, buf.msg_len, 0) == -1) {
307: ioDEBUG(3, "Error:: recv(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
1.2.2.9 misho 308: finiSession(sess);
1.2 misho 309: return NULL;
310: }
311: } else {
312: sess = TASK_DATA(task);
313: buf.msg_len = TASK_DATLEN(task) > sizeof basebuf ? sizeof basebuf : TASK_DATLEN(task);
314: memcpy(buf.msg_base, sess->sess_buf->msg_base, buf.msg_len);
315: }
316:
317: cack = mqtt_readCONNECT(&buf, &sess->sess_ka, sess->sess_cid, sizeof sess->sess_cid,
318: sess->sess_user, sizeof sess->sess_user, sess->sess_pass, sizeof sess->sess_pass,
319: &sess->sess_will.topic, &sess->sess_will.msg);
320: ret = cack.retcode;
321: flg.flags = cack.reserved;
322: if (flg.reserved) {
323: ioDEBUG(3, "Error:: in MQTT protocol #%d - %s", mqtt_GetErrno(), mqtt_GetError());
324: goto end;
325: } else {
326: sess->sess_clean = flg.clean_sess;
327: sess->sess_will.qos = flg.will_qos;
328: sess->sess_will.retain = flg.will_retain;
329: sess->sess_will.flag = flg.will_flg;
330: }
331:
1.2.2.11! misho 332: printf("sql=%p\n", acc);
! 333: fflush(stdout);
1.2 misho 334: /* check online table for user */
335: if (call.LoginACC(&cfg, acc, sess->sess_user, sess->sess_pass) < 1) {
336: ioDEBUG(0, "Login:: DENIED for username %s and password %s",
337: sess->sess_user, sess->sess_pass);
338: ret = MQTT_RETCODE_DENIED;
339: goto end;
340: } else {
341: ioDEBUG(1, "Login:: ALLOWED for username %s ...", sess->sess_user);
342: ret = MQTT_RETCODE_ACCEPTED;
343: }
1.2.2.11! misho 344: printf(".sql=%p\n", pub);
! 345: fflush(stdout);
1.2 misho 346: if (call.FiniSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, "%") > 0) {
347: ioDEBUG(2, "Old session %s should be disconnect!", sess->sess_cid);
348: TAILQ_FOREACH(s, &Sessions, sess_node)
349: if (!strcmp(s->sess_cid, sess->sess_cid)) {
350: /* found stale session & disconnect it! */
351: stopSession(s);
352: break;
353: }
354: }
1.2.2.11! misho 355: printf("...sql=%p\n", pub);
! 356: fflush(stdout);
1.2 misho 357: if (call.InitSessPUB(&cfg, pub, sess->sess_cid, sess->sess_user, sess->sess_addr,
358: sess->sess_will.flag, sess->sess_will.topic, sess->sess_will.msg,
359: sess->sess_will.qos, sess->sess_will.retain) == -1) {
360: ioDEBUG(0, "Session %s DENIED for username %s", sess->sess_cid, sess->sess_user);
361: ret = MQTT_RETCODE_DENIED;
362: goto end;
363: } else {
364: ioDEBUG(0, "Session %s from %s and username %s is started",
365: sess->sess_cid, sess->sess_addr, sess->sess_user);
366: ret = MQTT_RETCODE_ACCEPTED;
367: }
368:
369: ret = mqtt_msgCONNACK(&msg, ret);
370: if ((ret = send(sess->sess_sock, msg.msg_base, ret, 0)) == -1) {
371: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
1.2.2.9 misho 372: finiSession(sess);
1.2 misho 373: return NULL;
374: } else {
375: ioDEBUG(5, "Sended %d bytes", ret);
376: free(msg.msg_base);
377: memset(&msg, 0, sizeof msg);
378: }
379:
380: /* Start session thread OK ... */
1.2.2.6 misho 381: SESS_LOCK;
1.2 misho 382: TAILQ_INSERT_TAIL(&Sessions, sess, sess_node);
1.2.2.11! misho 383: pthread_create(&sess->sess_tid, NULL, (void*(*)(void*)) thrSession, sess);
! 384: pthread_detach(sess->sess_tid);
1.2.2.6 misho 385: SESS_UNLOCK;
1.2 misho 386:
387: call.LOG(logg, "Session %s started from %s for user %s (timeout=%d) OK!\n", sess->sess_cid,
388: sess->sess_addr, sess->sess_user, sess->sess_ka);
389: return NULL;
390: end: /* close client connection */
391: ret = mqtt_msgCONNACK(&msg, ret);
392: if ((ret = send(sess->sess_sock, msg.msg_base, ret, 0)) == -1) {
393: ioDEBUG(3, "Error:: send(%d) #%d - %s", sess->sess_sock, errno, strerror(errno));
394: } else {
395: ioDEBUG(5, "Sended %d bytes", ret);
396: free(msg.msg_base);
397: memset(&msg, 0, sizeof msg);
398: }
399:
400: ioDEBUG(1, "Close client %s with socket=%d", sess->sess_addr, sess->sess_sock);
1.2.2.9 misho 401: finiSession(sess);
1.2 misho 402: return NULL;
403: }
404:
405: static void *
1.2.2.9 misho 406: acceptClient(sched_task_t *task)
1.2 misho 407: {
1.2.2.9 misho 408: int cli;
409: io_sockaddr_t sa;
410: socklen_t sslen = sizeof sa.ss;
411: ait_val_t *v;
412: char str[STRSIZ];
1.2 misho 413:
1.2.2.9 misho 414: ioTRACE(4);
1.2 misho 415:
1.2.2.9 misho 416: assert(task);
1.2 misho 417:
1.2.2.9 misho 418: if ((cli = accept(TASK_FD(task), &sa.sa, &sslen)) == -1)
419: goto end;
420: else
421: fcntl(TASK_FD(task), F_SETFL, fcntl(TASK_FD(task), F_GETFL, 0) | O_NONBLOCK);
422:
423: v = io_allocVar();
424: if (!v) {
425: ioLIBERR(io);
426: close(cli);
427: goto end;
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));
434:
435: if (!schedRead(root, startSession, v, cli, NULL, 0)) {
436: io_freeVar(v);
437: close(cli);
438: ioDEBUG(1, "Terminated client with socket=%d", cli);
439: }
440: end:
1.2.2.11! misho 441: if (!schedRead(TASK_ROOT(task), acceptClient, NULL, TASK_FD(task), NULL, 0))
! 442: ioLIBERR(sched);
1.2.2.9 misho 443: return NULL;
1.2 misho 444: }
445:
1.2.2.9 misho 446: /* ----------------------------------------------------------------------- */
447:
1.2 misho 448: int
449: Run(int sock)
450: {
1.2.2.9 misho 451: struct tagPub *pub;
452: struct timespec pl = { 0, 100000000 };
1.2 misho 453:
454: ioTRACE(1);
455:
1.2.2.9 misho 456: if (listen(sock, SOMAXCONN) == -1) {
1.2 misho 457: ioSYSERR(0);
458: return -1;
459: } else
1.2.2.9 misho 460: fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
1.2 misho 461:
1.2.2.9 misho 462: /* state machine - accept new connections */
463: if (!schedRead(root, acceptClient, NULL, sock, NULL, 0)) {
464: ioLIBERR(sched);
1.2 misho 465: return -1;
466: }
467:
1.2.2.10 misho 468: pthread_attr_init(&attr);
469: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
470:
1.2.2.9 misho 471: schedPolling(root, &pl, NULL);
472: schedRun(root, &Kill);
1.2 misho 473:
1.2.2.10 misho 474: pthread_attr_destroy(&attr);
475:
1.2.2.9 misho 476: /* free all undeleted elements into lists */
477: PUBS_LOCK;
478: TAILQ_FOREACH(pub, &Pubs, pub_node) {
479: TAILQ_REMOVE(&Pubs, pub, pub_node);
480:
481: AIT_FREE_VAL(&pub->pub_name);
482: if (pub->pub_packet.msg_base)
483: free(pub->pub_packet.msg_base);
1.2 misho 484: }
1.2.2.9 misho 485: PUBS_UNLOCK;
1.2 misho 486: return 0;
487: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>