#import "MTNetworkUsageManager.h" #include #import #if defined(MtProtoKitDynamicFramework) # import # import # import # import #elif defined(MtProtoKitMacFramework) # import # import # import # import #else # import # import # import # import #endif @interface MTNetworkUsageManager () { MTQueue *_queue; MTNetworkUsageCalculationInfo *_info; NSUInteger _pendingIncomingBytes; NSUInteger _pendingOutgoingBytes; int _fd; void *_map; } @end @implementation MTNetworkUsageManager - (instancetype)initWithInfo:(MTNetworkUsageCalculationInfo *)info { self = [super init]; if (self != nil) { _queue = [[MTQueue alloc] init]; _info = info; [_queue dispatchOnQueue:^{ NSString *path = info.filePath; int32_t fd = open([path UTF8String], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd >= 0) { _fd = fd; ftruncate(fd, 4096); void *map = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map != MAP_FAILED) { _map = map; } } }]; } return self; } - (void)dealloc { void *map = _map; int32_t fd = _fd; [_queue dispatchOnQueue:^{ if (map) { munmap(map, 4096); } if (fd > 0) { close(fd); } }]; } static int offsetForInterface(MTNetworkUsageCalculationInfo *info, MTNetworkUsageManagerInterface interface, bool incoming) { switch (interface) { case MTNetworkUsageManagerInterfaceWWAN: if (incoming) { return info.incomingWWANKey * 8; } else { return info.outgoingWWANKey * 8; } case MTNetworkUsageManagerInterfaceOther: if (incoming) { return info.incomingOtherKey * 8; } else { return info.outgoingOtherKey * 8; } } } - (void)addIncomingBytes:(NSUInteger)incomingBytes interface:(MTNetworkUsageManagerInterface)interface { [_queue dispatchOnQueue:^{ if (_map) { int64_t *ptr = (int64_t *)(_map + offsetForInterface(_info, interface, true)); OSAtomicAdd64((int64_t)incomingBytes, ptr); } }]; } - (void)addOutgoingBytes:(NSUInteger)outgoingBytes interface:(MTNetworkUsageManagerInterface)interface { [_queue dispatchOnQueue:^{ if (_map) { int64_t *ptr = (int64_t *)(_map + offsetForInterface(_info, interface, false)); OSAtomicAdd64((int64_t)outgoingBytes, ptr); } }]; } - (void)resetKeys:(NSArray *)keys setKeys:(NSDictionary *)setKeys completion:(void (^)())completion { [_queue dispatchOnQueue:^{ if (_map) { for (NSNumber *key in keys) { int64_t *ptr = (int64_t *)(_map + [key intValue] * 8); *ptr = 0; } [setKeys enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *value, __unused BOOL *stop) { int64_t *ptr = (int64_t *)(_map + [key intValue] * 8); *ptr = [value longLongValue]; }]; if (completion) { completion(); } } }]; } - (MTSignal *)currentStatsForKeys:(NSArray *)keys { return [[MTSignal alloc] initWithGenerator:^id(MTSubscriber *subscriber) { [_queue dispatchOnQueue:^{ if (_map) { NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; for (NSNumber *key in keys) { int64_t *ptr = (int64_t *)(_map + [key intValue] * 8); result[key] = @(*ptr); } [subscriber putNext:result]; } else { [subscriber putNext:nil]; } [subscriber putCompletion]; }]; return nil; }]; } @end