/* 删除与套接字 fd 相关的不完整的数据包. 这个函数只会在套接字发生错误或者关闭时调用. * 参数: L 是 Lua 虚拟机栈, 其位置一就是 queue 数据结构; fd 是套接字 id; */ static void close_uncomplete(lua_State *L, int fd) { struct queue *q = lua_touserdata(L,1); struct uncomplete * uc = find_uncomplete(q, fd); if (uc) { skynet_free(uc->pack.buffer); skynet_free(uc); } }
/* [lua_api] 将套接字发送过来的数据返回给 Lua 层使用. 函数首先将检查 queue 的不完整数据包哈希表中是否存在套接字 fd 的 * 不完整数据包, 如果有则检查其已经读取的内容长度, 并将剩余部分复制过去, 如果刚好是一个数据包大小就直接返回 "data" 字符 * 串和数据包给 Lua 层, 如果复制后多于一个数据包, 则将这些数据包一起插入到 queue 中, 并返回 "more" 字符串给 Lua 层. * 在不足一个数据包的情况下, 将不完整包重新插入到哈希表中. 对于之前没有不完整包的情况执行相同的流程. 当返回 "more" 时, * 可以通过 lpop 函数取得 queue 中的数据包. buffer 中的内容会复制到新的内存块中, 因而在调用完此函数之后需要释放 buffer 的内存; * * 参数: L 是虚拟机栈, 其位置一就是 queue 数据结构; fd 是套接字 id; buffer 是数据内容; size 是数据大小; * * 返回: userdata[1] 为 queue 数据结构; string/nil[2] 为 "more" 或者 "data" 表示有数据, nil 表示数据不完整; * int[3] 为套接字 id, 仅在 "data" 下返回; lightuserdata[4] 为数据内容, 仅在 "data" 下返回; * int[5] 为数据大小, 仅在 "data" 下返回; */ static int filter_data_(lua_State *L, int fd, uint8_t * buffer, int size) { struct queue *q = lua_touserdata(L,1); struct uncomplete * uc = find_uncomplete(q, fd); if (uc) { // fill uncomplete if (uc->read < 0) { // read size assert(uc->read == -1); int pack_size = *buffer; pack_size |= uc->header << 8 ; ++buffer; --size; uc->pack.size = pack_size; uc->pack.buffer = skynet_malloc(pack_size); uc->read = 0; } int need = uc->pack.size - uc->read; if (size < need) { memcpy(uc->pack.buffer + uc->read, buffer, size); uc->read += size; int h = hash_fd(fd); uc->next = q->hash[h]; q->hash[h] = uc; return 1; } memcpy(uc->pack.buffer + uc->read, buffer, need); buffer += need; size -= need; if (size == 0) { lua_pushvalue(L, lua_upvalueindex(TYPE_DATA)); lua_pushinteger(L, fd); lua_pushlightuserdata(L, uc->pack.buffer); lua_pushinteger(L, uc->pack.size); skynet_free(uc); return 5; } // more data push_data(L, fd, uc->pack.buffer, uc->pack.size, 0); skynet_free(uc); push_more(L, fd, buffer, size); lua_pushvalue(L, lua_upvalueindex(TYPE_MORE)); return 2; } else { if (size == 1) { struct uncomplete * uc = save_uncomplete(L, fd); uc->read = -1; uc->header = *buffer; return 1; } int pack_size = read_size(buffer); buffer+=2; size-=2; if (size < pack_size) { struct uncomplete * uc = save_uncomplete(L, fd); uc->read = size; uc->pack.size = pack_size; uc->pack.buffer = skynet_malloc(pack_size); memcpy(uc->pack.buffer, buffer, size); return 1; } if (size == pack_size) { // just one package lua_pushvalue(L, lua_upvalueindex(TYPE_DATA)); lua_pushinteger(L, fd); void * result = skynet_malloc(pack_size); memcpy(result, buffer, size); lua_pushlightuserdata(L, result); lua_pushinteger(L, size); return 5; } // more data push_data(L, fd, buffer, pack_size, 1); buffer += pack_size; size -= pack_size; push_more(L, fd, buffer, size); lua_pushvalue(L, lua_upvalueindex(TYPE_MORE)); return 2; } }
/// 从 buffer 读取数据, 返回 lua 函数返回值的个数, 函数的第一个返回值是 queue. static int filter_data_(lua_State *L, int fd, uint8_t * buffer, int size) { struct queue *q = lua_touserdata(L, 1); struct uncomplete * uc = find_uncomplete(q, fd); // 注意, 这里将 uncomplete 从 queue.hash 中移除了 if (uc) { // fill uncomplete // 填充 uncomplete if (uc->read < 0) { // 当包头还未完整读取的情况 // read size assert(uc->read == -1); // 获得数据内容大小 int pack_size = *buffer; pack_size |= uc->header << 8 ; // 偏移到实际数据内容指针开始位置 ++buffer; // 实际的数据内容大小 --size; uc->pack.size = pack_size; // 记录实际需要读取的内容大小 uc->pack.buffer = skynet_malloc(pack_size); // 分配内存空间 uc->read = 0; // 标记还未开始读取数据内容 } // 计算需要读取的数据 int need = uc->pack.size - uc->read; if (size < need) { // 如果 buffer 待读取的数据还不足, 尽可能读取能够读取的数据 // 读取可读的数据 memcpy(uc->pack.buffer + uc->read, buffer, size); uc->read += size; // 再次压入到 queue.hash 中 int h = hash_fd(fd); uc->next = q->hash[h]; q->hash[h] = uc; return 1; } // 读取完整的数据内容 memcpy(uc->pack.buffer + uc->read, buffer, need); // 跳过已经读取的内容 buffer += need; // 计算剩余的可读取数据大小 size -= need; // buffer 中的数据恰好足够读取 if (size == 0) { lua_pushvalue(L, lua_upvalueindex(TYPE_DATA)); // macro TYPE_DATA lua_pushinteger(L, fd); // socket id lua_pushlightuserdata(L, uc->pack.buffer); // buffer lua_pushinteger(L, uc->pack.size); // buffer size skynet_free(uc); return 5; } // more data // buffer 有更多的数据可读, 将数据压入 queue.queue 中 push_data(L, fd, uc->pack.buffer, uc->pack.size, 0); skynet_free(uc); push_more(L, fd, buffer, size); // 继续读取剩下的数据 lua_pushvalue(L, lua_upvalueindex(TYPE_MORE)); // macro TYPE_MORE return 2; } else { if (size == 1) { // 仅读取包头的 1 个数据 struct uncomplete * uc = save_uncomplete(L, fd); uc->read = -1; uc->header = *buffer; return 1; } // 读取包头的数据 int pack_size = read_size(buffer); buffer+=2; size-=2; // 如果 buffer 的数据不够读, 将 buffer 数据全部读取 if (size < pack_size) { struct uncomplete * uc = save_uncomplete(L, fd); uc->read = size; uc->pack.size = pack_size; uc->pack.buffer = skynet_malloc(pack_size); memcpy(uc->pack.buffer, buffer, size); return 1; } // 如果 buffer 的数据恰好是 1 个包的数据大小, 将 buffer 数据全部读取 if (size == pack_size) { // just one package lua_pushvalue(L, lua_upvalueindex(TYPE_DATA)); // macro TYPE_DATA lua_pushinteger(L, fd); // socket id void * result = skynet_malloc(pack_size); memcpy(result, buffer, size); lua_pushlightuserdata(L, result); // buffer lua_pushinteger(L, size); // buffer size return 5; } // more data // 如果 buffer 的数据大于 1 个包的数据大小, 那么继续读取 buffer 里面的数据 push_data(L, fd, buffer, pack_size, 1); buffer += pack_size; size -= pack_size; push_more(L, fd, buffer, size); lua_pushvalue(L, lua_upvalueindex(TYPE_MORE)); // macro TYPE_MORE return 2; } }