1 /*
2  * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *   * Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *   * Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *   * Neither the name of Redis nor the names of its contributors may be used
15  *     to endorse or promote products derived from this software without
16  *     specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef __HIREDIS_AE_H__
32 #define __HIREDIS_AE_H__
33 #include <sys/types.h>
34 #include <ae.h>
35 #include "../hiredis.h"
36 #include "../async.h"
37 
38 typedef struct redisAeEvents {
39     redisAsyncContext *context;
40     aeEventLoop *loop;
41     int fd;
42     int reading, writing;
43 } redisAeEvents;
44 
redisAeReadEvent(aeEventLoop * el,int fd,void * privdata,int mask)45 static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
46     ((void)el); ((void)fd); ((void)mask);
47 
48     redisAeEvents *e = (redisAeEvents*)privdata;
49     redisAsyncHandleRead(e->context);
50 }
51 
redisAeWriteEvent(aeEventLoop * el,int fd,void * privdata,int mask)52 static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
53     ((void)el); ((void)fd); ((void)mask);
54 
55     redisAeEvents *e = (redisAeEvents*)privdata;
56     redisAsyncHandleWrite(e->context);
57 }
58 
redisAeAddRead(void * privdata)59 static void redisAeAddRead(void *privdata) {
60     redisAeEvents *e = (redisAeEvents*)privdata;
61     aeEventLoop *loop = e->loop;
62     if (!e->reading) {
63         e->reading = 1;
64         aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e);
65     }
66 }
67 
redisAeDelRead(void * privdata)68 static void redisAeDelRead(void *privdata) {
69     redisAeEvents *e = (redisAeEvents*)privdata;
70     aeEventLoop *loop = e->loop;
71     if (e->reading) {
72         e->reading = 0;
73         aeDeleteFileEvent(loop,e->fd,AE_READABLE);
74     }
75 }
76 
redisAeAddWrite(void * privdata)77 static void redisAeAddWrite(void *privdata) {
78     redisAeEvents *e = (redisAeEvents*)privdata;
79     aeEventLoop *loop = e->loop;
80     if (!e->writing) {
81         e->writing = 1;
82         aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e);
83     }
84 }
85 
redisAeDelWrite(void * privdata)86 static void redisAeDelWrite(void *privdata) {
87     redisAeEvents *e = (redisAeEvents*)privdata;
88     aeEventLoop *loop = e->loop;
89     if (e->writing) {
90         e->writing = 0;
91         aeDeleteFileEvent(loop,e->fd,AE_WRITABLE);
92     }
93 }
94 
redisAeCleanup(void * privdata)95 static void redisAeCleanup(void *privdata) {
96     redisAeEvents *e = (redisAeEvents*)privdata;
97     redisAeDelRead(privdata);
98     redisAeDelWrite(privdata);
99     free(e);
100 }
101 
redisAeAttach(aeEventLoop * loop,redisAsyncContext * ac)102 static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
103     redisContext *c = &(ac->c);
104     redisAeEvents *e;
105 
106     /* Nothing should be attached when something is already attached */
107     if (ac->ev.data != NULL)
108         return REDIS_ERR;
109 
110     /* Create container for context and r/w events */
111     e = (redisAeEvents*)malloc(sizeof(*e));
112     e->context = ac;
113     e->loop = loop;
114     e->fd = c->fd;
115     e->reading = e->writing = 0;
116 
117     /* Register functions to start/stop listening for events */
118     ac->ev.addRead = redisAeAddRead;
119     ac->ev.delRead = redisAeDelRead;
120     ac->ev.addWrite = redisAeAddWrite;
121     ac->ev.delWrite = redisAeDelWrite;
122     ac->ev.cleanup = redisAeCleanup;
123     ac->ev.data = e;
124 
125     return REDIS_OK;
126 }
127 #endif
128