//读取事件触发调用函数
int ZCE_Event_INotify::handle_input ()
{

#if defined (ZCE_OS_LINUX)

    ZCE_LOG(RS_DEBUG, "ZCE_Event_INotify::handle_input");

    int detect_ret = 0;
    size_t watch_event_num = 0;

    //读取
    ssize_t read_ret = ZCE_LIB::read(inotify_handle_, read_buffer_, READ_BUFFER_LEN);
    if (read_ret <= 0)
    {
        return -1;
    }

    uint32_t read_len = static_cast<uint32_t>(read_ret);
    uint32_t next_entry_offset = 0;

    //可能一次读取出来多个inotify_event数据,所以要循环处理
    do
    {
        detect_ret = 0;

        ::inotify_event *ne_ptr = (::inotify_event *) (read_buffer_ + next_entry_offset);

        //检查读取的数据是否还有一个,
        read_len -= (sizeof(::inotify_event) + ne_ptr->len);
        next_entry_offset += sizeof(::inotify_event) + ne_ptr->len;

        HDL_TO_EIN_MAP::iterator active_iter = watch_event_map_.find(ne_ptr->wd);
        if (active_iter == watch_event_map_.end())
        {
            //某个FD在MAP中间无法找到,最大的可能是
            ZCE_LOG(RS_DEBUG,
                    "You code error or a handle not in map (delete in this do while), please check you code. handle[%u]",
                    ne_ptr->wd);
            continue;
        }
        EVENT_INOTIFY_NODE *node_ptr = &(active_iter->second);
        const char *active_path = ne_ptr->name;
        //根据返回的mask决定如何处理

        //注意下面的代码分支用的if else if ,而不是if if,我的初步看法是这些事件不会一起触发,但也许不对。
        //下面5个是和Windows 共有的,
        uint32_t event_mask = ne_ptr->mask;
        if (event_mask & IN_CREATE )
        {
            detect_ret = inotify_create(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if (event_mask & IN_DELETE  )
        {
            detect_ret = inotify_delete(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if ( event_mask & IN_MODIFY )
        {
            detect_ret = inotify_modify(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if ( event_mask & IN_MOVED_FROM)
        {
            detect_ret = inotify_moved_from(node_ptr->watch_handle_,
                                            event_mask,
                                            node_ptr->watch_path_,
                                            active_path);
        }
        else if ( event_mask & IN_MOVED_TO)
        {
            detect_ret = inotify_moved_to(node_ptr->watch_handle_,
                                          event_mask,
                                          node_ptr->watch_path_,
                                          active_path);
        }
        //下面这些是LINUX自己特有的
        else if ( event_mask & IN_ACCESS)
        {
            detect_ret = inotify_access(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if (event_mask & IN_OPEN)
        {
            detect_ret = inotify_open(node_ptr->watch_handle_,
                                      event_mask,
                                      node_ptr->watch_path_,
                                      active_path);
        }
        else if (event_mask & IN_CLOSE_WRITE || event_mask | IN_CLOSE_NOWRITE)
        {
            detect_ret = inotify_close(node_ptr->watch_handle_,
                                       event_mask,
                                       node_ptr->watch_path_,
                                       active_path);
        }
        else if (event_mask & IN_ATTRIB)
        {
            detect_ret = inotify_attrib(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if (event_mask & IN_MOVE_SELF)
        {
            detect_ret = inotify_move_slef(node_ptr->watch_handle_,
                                           event_mask,
                                           node_ptr->watch_path_,
                                           active_path);
        }
        else if (event_mask & IN_DELETE_SELF)
        {
            detect_ret = inotify_delete_slef(node_ptr->watch_handle_,
                                             event_mask,
                                             node_ptr->watch_path_,
                                             active_path);
        }

        //返回-1,关闭之,
        if (detect_ret == -1)
        {
            rm_watch(node_ptr->watch_handle_);
        }

        //累计发现事件计数
        ++(watch_event_num);

    }
    while (read_len > 0);

    return 0;

#elif defined (ZCE_OS_WINDOWS)

    int detect_ret = 0;
    DWORD num_read = 0;
    BOOL bret = ::GetOverlappedResult(watch_handle_,
                                      &over_lapped_,
                                      &num_read,
                                      FALSE);

    //读取结果失败
    if (FALSE == bret)
    {
        ZCE_LOG(RS_ERROR, "[%s] ::GetOverlappedResult fail,error [%u].",
                __ZCE_FUNC__,
                ZCE_LIB::last_error());
        return -1;
    }


    //记录当前处理的句柄,


    FILE_NOTIFY_INFORMATION *read_ptr = NULL;
    DWORD next_entry_offset = 0;
    do
    {
        detect_ret = 0;
        read_ptr = (FILE_NOTIFY_INFORMATION *)(read_buffer_ + next_entry_offset);

        //文件名称进行转换,从宽字节转换为多字节,
        //天杀的Windows在这些地方又埋了陷阱FILE_NOTIFY_INFORMATION里面的长度FileNameLength是字节长度
        //而WideCharToMultiByte函数需要的长度是字长度,你能TMD统一一点吗?
        int length_of_ws = ::WideCharToMultiByte(CP_ACP,
                                                 0,
                                                 read_ptr->FileName,
                                                 read_ptr->FileNameLength / sizeof(wchar_t),
                                                 NULL,
                                                 0,
                                                 NULL,
                                                 NULL);
        //Windows 的目录名称最大长度可以到3K,我没有兴趣去搞一套这个玩
        if (length_of_ws >= MAX_PATH)
        {
            ZCE_LOG(RS_ALERT, "My God ,your path length [%u] more than MAX_PATH [%u],I don't process this.",
                    length_of_ws,
                    MAX_PATH);
            continue;
        }
        char active_path[MAX_PATH + 1];
        ::WideCharToMultiByte(CP_ACP,
                              0,
                              read_ptr->FileName,
                              read_ptr->FileNameLength / sizeof(wchar_t),
                              active_path,
                              length_of_ws,
                              NULL,
                              NULL);
        active_path[length_of_ws] = '\0';

        //根据Action和mask确定调用函数
        switch (read_ptr->Action)
        {
            case FILE_ACTION_ADDED:
                if (watch_mask_ | IN_CREATE)
                {
                    detect_ret = inotify_create(watch_handle_,
                                                watch_mask_,
                                                watch_path_,
                                                active_path);
                }
                break;
            case FILE_ACTION_REMOVED:
                if (watch_mask_ | IN_DELETE)
                {
                    detect_ret = inotify_delete(watch_handle_,
                                                watch_mask_,
                                                watch_path_,
                                                active_path);
                }
                break;
                //注意Windows 下的这个类型,包括了属性更改
            case FILE_ACTION_MODIFIED:
                if (watch_mask_ | IN_MODIFY)
                {
                    detect_ret = inotify_modify(watch_handle_,
                                                watch_mask_,
                                                watch_path_,
                                                active_path);
                }
                break;
            case FILE_ACTION_RENAMED_OLD_NAME:
                if (watch_mask_ | IN_MOVED_FROM)
                {
                    detect_ret = inotify_moved_from(watch_handle_,
                                                    watch_mask_,
                                                    watch_path_,
                                                    active_path);
                }
                break;
            case FILE_ACTION_RENAMED_NEW_NAME:
                if (watch_mask_ | IN_MOVED_TO)
                {
                    detect_ret = inotify_moved_to(watch_handle_,
                                                  watch_mask_,
                                                  watch_path_,
                                                  active_path);
                }
                break;
        }

        //累计偏移长度
        next_entry_offset += read_ptr->NextEntryOffset;

        //返回-1,关闭之
        if (detect_ret == -1)
        {
            handle_close();
        }

        //为什么要这样做,因为上面的处理过程,可能有人已经调用了rm_watch,或者handle_close,
        if (watch_handle_ == ZCE_INVALID_HANDLE)
        {
            return 0;
        }

    }
    while (read_ptr->NextEntryOffset != 0);

    DWORD bytes_returned = 0;

    //继续进行监控处理
    bret = ::ReadDirectoryChangesW(
               watch_handle_,            // handle to directory
               read_buffer_, // read results buffer
               READ_BUFFER_LEN,                               // length of buffer
               watch_sub_dir_,                                 // monitoring option
               FILE_NOTIFY_CHANGE_SECURITY |
               FILE_NOTIFY_CHANGE_CREATION |
               FILE_NOTIFY_CHANGE_LAST_ACCESS |
               FILE_NOTIFY_CHANGE_LAST_WRITE |
               FILE_NOTIFY_CHANGE_SIZE |
               FILE_NOTIFY_CHANGE_ATTRIBUTES |
               FILE_NOTIFY_CHANGE_DIR_NAME |
               FILE_NOTIFY_CHANGE_FILE_NAME,          // filter conditions
               &bytes_returned,                       // bytes returned
               & (over_lapped_), // overlapped buffer
               NULL                                   // completion routine
           );
    if (FALSE == bret)
    {
        ZCE_LOG(RS_ERROR, "[zcelib][%s] ::ReadDirectoryChangesW fail,error [%u].",
                __ZCE_FUNC__,
                ZCE_LIB::last_error());
    }

    return 0;

#endif
}
Exemple #2
0
int ENTRY_NAME(int argc, const char* argv[]) {
    const char **p = alloca(argc * sizeof(char*));
    struct master_config config;
    char* keybuf;

    memcpy(p, argv + 1, (argc - 1) * sizeof(char*));
    p[argc - 1] = 0;

    if (--argc == 0) {
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "\tmultex --dev <name> --interface <name> \n");
        return 2;
    }

    config.interfaces.next = &config.interfaces;
    config.sessions.next = &config.sessions;
    config.endpoints.next = &config.endpoints;
    config.rendpoints.next = &config.rendpoints;
    config.port = 1389;
    config.event_base = event_base_new();
    config.tracker = tracker_create(config.event_base, &config, (tracker_callback_t)tracker_callback);
    if (config.tracker == 0) {
        return 1;
    }

    config.cipher = cipher_bf();
    config.cipher_keysize = cipher_keysize(config.cipher);
    config.cipher_size = cipher_blocksize(config.cipher);
    keybuf = alloca(config.cipher_keysize);

    config.trackerhost = "tracker.publicbt.com:80";
    memset(keybuf, 0, config.cipher_keysize);
    config.key0 = cipher_context_create(config.cipher, keybuf);
    random_bytes(keybuf, config.cipher_keysize);
    config.keyX = cipher_context_create(config.cipher, keybuf);

    config.digest = digest_context_create(digest_sha());
    config.digest_size = digest_size(digest_sha());

    while (*p != 0) {
        const char* cmd = *p++;
        if (strcmp(cmd, "--tracker") == 0) {
            if (*p == 0) {
                fprintf(stderr, "tracker address expected\n");
                return 2;
            }
            tracker_add(config.tracker, *p++);
            continue;
        }
        if (strcmp(cmd, "--remote") == 0) {
            struct udpaddress address;
            if (*p == 0) {
                fprintf(stderr, "remote address expected\n");
                return 2;
            }
            udpaddress_resolve(&address, *p++);
            tracker_callback(&config, &address, 0);
            continue;
        }
        if (strcmp(cmd, "--dev") == 0) {
            if (*p == 0) {
                fprintf(stderr, "Device name expected\n");

                return 2;
            }
            fprintf(stderr, "Creating device %s...\n", *p);
            config.master_fd = tun_create(*p++);
            if (config.master_fd < 0) {
                return 1;
            }
            config.master_event = event_new(config.event_base, config.master_fd, EV_READ | EV_PERSIST, (event_callback_fn)master_callback, &config);
            event_add(config.master_event, 0);
            continue;
        }
        if (strcmp(cmd, "--interface") == 0 || strcmp(cmd, "-i") == 0) {

            const char *name = *p++;
            struct interface *interface = malloc(sizeof(struct interface));

            if (name == 0) {
                fprintf(stderr, "interface name expected\n");
                return 2;
            }

            interface->priority = 1;
            interface->weight = 1;
            interface->name = strdup(name);
            interface->next = config.interfaces.next;
            interface->active = 0;
            config.interfaces.next = interface;
            continue;
        }
        fprintf(stderr, "Unknown option: %s\n", cmd);
        return 2;
    }

    /*open interfaces*/
    config.inotify = inotify_create(config.event_base, &config, (inotification_callback_t)inotify_callback);
    if (config.inotify == 0) {
        return 1;
    }


    {
        struct if_nameindex *ifp = if_nameindex();
        struct if_nameindex *p = ifp;
        struct ifaddrs *ifaddr;
        struct ifaddrs *ifa;

        if (getifaddrs(&ifaddr) == -1) {
            perror("getifaddrs");
            return 1;
        }

        while (p->if_index > 0 && p->if_name != 0) {
            struct inotification notification;

            notification.device = p->if_name;
            notification.type = INOTIFY_INT_ADDED;
            inotify_callback(&config, &notification);

            for (ifa = ifaddr; ifa != 0; ifa = ifa->ifa_next) {
               notification.address.family = ifa->ifa_addr->sa_family;
               if (strcmp(ifa->ifa_name, p->if_name) != 0) {
                   continue;
               }
               notification.type = INOTIFY_ADDR_ADDED;
               /* For an AF_INET* interface address, display the address */
               if (notification.address.family == AF_INET) {
                    notification.address.addr4 =  ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
               } else
               if (notification.address.family == AF_INET6) {
                    notification.address.addr6 =  ((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
               } else {
                    continue;
               }
               inotify_callback(&config, &notification);
           }

            p++;
        }
        if_freenameindex(ifp);

        freeifaddrs(ifaddr);

    }

    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
    config.stdin_event = event_new(config.event_base, STDIN_FILENO, EV_READ | EV_PERSIST, (event_callback_fn)stdin_callback, &config);
    event_add(config.stdin_event, 0);

    {
        struct timeval timeval;
        timeval.tv_sec = 10;
        timeval.tv_usec = 0;
        config.reconnect_event = event_new(config.event_base, -1, EV_PERSIST, (event_callback_fn)reconnect_callback, &config);
        evtimer_add(config.reconnect_event, &timeval);
    }

    reconnect_callback(-1, EV_TIMEOUT, &config);
    event_base_dispatch(config.event_base);


    return 0;
}