summaryrefslogtreecommitdiff
path: root/adapters/macosx.h
blob: 3c87f1b2faafafcdae4b857003dd43dcf53e63be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
//  Created by Дмитрий Бахвалов on 13.07.15.
//  Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved.
//

#ifndef __HIREDIS_MACOSX_H__
#define __HIREDIS_MACOSX_H__

#include <CoreFoundation/CoreFoundation.h>

#include "../hiredis.h"
#include "../async.h"

typedef struct {
    redisAsyncContext *context;
    CFSocketRef socketRef;
    CFRunLoopSourceRef sourceRef;
} RedisRunLoop;

static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) {
    if( redisRunLoop != NULL ) {
        if( redisRunLoop->sourceRef != NULL ) {
            CFRunLoopSourceInvalidate(redisRunLoop->sourceRef);
            CFRelease(redisRunLoop->sourceRef);
        }
        if( redisRunLoop->socketRef != NULL ) {
            CFSocketInvalidate(redisRunLoop->socketRef);
            CFRelease(redisRunLoop->socketRef);
        }
        hi_free(redisRunLoop);
    }
    return REDIS_ERR;
}

static void redisMacOSAddRead(void *privdata) {
    RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
    CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack);
}

static void redisMacOSDelRead(void *privdata) {
    RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
    CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack);
}

static void redisMacOSAddWrite(void *privdata) {
    RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
    CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack);
}

static void redisMacOSDelWrite(void *privdata) {
    RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
    CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack);
}

static void redisMacOSCleanup(void *privdata) {
    RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
    freeRedisRunLoop(redisRunLoop);
}

static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) {
    redisAsyncContext* context = (redisAsyncContext*) info;

    switch (callbackType) {
        case kCFSocketReadCallBack:
            redisAsyncHandleRead(context);
            break;

        case kCFSocketWriteCallBack:
            redisAsyncHandleWrite(context);
            break;

        default:
            break;
    }
}

static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) {
    redisContext *redisCtx = &(redisAsyncCtx->c);

    /* Nothing should be attached when something is already attached */
    if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR;

    RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop));
    if (redisRunLoop == NULL)
        return REDIS_ERR;

    /* Setup redis stuff */
    redisRunLoop->context = redisAsyncCtx;

    redisAsyncCtx->ev.addRead  = redisMacOSAddRead;
    redisAsyncCtx->ev.delRead  = redisMacOSDelRead;
    redisAsyncCtx->ev.addWrite = redisMacOSAddWrite;
    redisAsyncCtx->ev.delWrite = redisMacOSDelWrite;
    redisAsyncCtx->ev.cleanup  = redisMacOSCleanup;
    redisAsyncCtx->ev.data     = redisRunLoop;

    /* Initialize and install read/write events */
    CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL };

    redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd,
                                                       kCFSocketReadCallBack | kCFSocketWriteCallBack,
                                                       redisMacOSAsyncCallback,
                                                       &socketCtx);
    if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop);

    redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0);
    if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop);

    CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode);

    return REDIS_OK;
}

#endif