static void _report(struct gate *g, struct skynet_context * ctx, const char * data, ...) { if (g->watchdog == 0) { return; } va_list ap; va_start(ap, data); char tmp[1024]; int n = vsnprintf(tmp, sizeof(tmp), data, ap); va_end(ap); skynet_send(ctx, 0, g->watchdog, 0, tmp, n, 0); }
static void response(struct skynet_context *ctx, struct package *P) { while (!queue_empty(&P->request)) { if (queue_empty(&P->response)) { break; } struct request req; struct response resp; queue_pop(&P->request, &req); queue_pop(&P->response, &resp); skynet_send(ctx, 0, req.source, PTYPE_RESPONSE | PTYPE_TAG_DONTCOPY, req.session, resp.msg, resp.sz); } }
static int _send(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); int session = 0; int index = 0; const char * dest = luaL_checkstring(L,1); if (lua_type(L,2) == LUA_TNUMBER) { session = lua_tointeger(L,2); ++index; } if (lua_gettop(L) == index + 1) { session = skynet_send(context, dest, session , NULL, 0); } else { int type = lua_type(L,index+2); if (type == LUA_TSTRING) { size_t len = 0; void * msg = (void *)lua_tolstring(L,index+2,&len); void * message = malloc(len); memcpy(message, msg, len); session = skynet_send(context, dest, session , message, len); } else if (type == LUA_TNIL) { session = skynet_send(context, dest, session , NULL, 0); } else { void * msg = lua_touserdata(L,index+2); if (msg == NULL) { return luaL_error(L, "skynet.send need userdata or string (%s)", lua_typename(L,type)); } int size = luaL_checkinteger(L,index+3); session = skynet_send(context, dest, session, msg, size); } } if (session < 0) { return luaL_error(L, "skynet.send drop the message to %s", dest); } lua_pushinteger(L,session); return 1; }
int master_init(struct master *m, struct skynet_context *ctx, const char * args) { char tmp[strlen(args) + 32]; sprintf(tmp,"gate L ! %s %d %d 0",args,PTYPE_HARBOR,REMOTE_MAX); const char * gate_addr = skynet_command(ctx, "LAUNCH", tmp); if (gate_addr == NULL) { skynet_error(ctx, "Master : launch gate failed"); return 1; } uint32_t gate = strtoul(gate_addr+1, NULL, 16); if (gate == 0) { skynet_error(ctx, "Master : launch gate invalid %s", gate_addr); return 1; } const char * self_addr = skynet_command(ctx, "REG", NULL); int n = sprintf(tmp,"broker %s",self_addr); skynet_send(ctx, 0, gate, PTYPE_TEXT, 0, tmp, n); skynet_send(ctx, 0, gate, PTYPE_TEXT, 0, "start", 5); skynet_callback(ctx, m, _mainloop); return 0; }
static int check_wsz(struct skynet_context *ctx, int id, void *buffer, int64_t wsz) { if (wsz < 0) { return -1; } else if (wsz > 1024 * 1024) { struct skynet_socket_message tmp; tmp.type = SKYNET_SOCKET_TYPE_WARNING; tmp.id = id; tmp.ud = (int)(wsz / 1024); tmp.buffer = NULL; skynet_send(ctx, 0, skynet_context_handle(ctx), PTYPE_SOCKET, 0 , &tmp, sizeof(tmp)); // skynet_error(ctx, "%d Mb bytes on socket %d need to send out", (int)(wsz / (1024 * 1024)), id); } return 0; }
static void socket_message(struct skynet_context *ctx, struct package *P, const struct skynet_socket_message * smsg) { switch (smsg->type) { case SKYNET_SOCKET_TYPE_CONNECT: if (P->init == 0 && smsg->id == P->fd) { skynet_send(ctx, 0, P->manager, PTYPE_TEXT, 0, "SUCC", 4); P->init = 1; } break; case SKYNET_SOCKET_TYPE_CLOSE: case SKYNET_SOCKET_TYPE_ERROR: if (P->init == 0 && smsg->id == P->fd) { skynet_send(ctx, 0, P->manager, PTYPE_TEXT, 0, "FAIL", 4); P->init = 1; } if (smsg->id != P->fd) { skynet_error(ctx, "Invalid fd (%d), should be (%d)", smsg->id, P->fd); } else { // todo: log when SKYNET_SOCKET_TYPE_ERROR response(ctx, P); service_exit(ctx, P); } break; case SKYNET_SOCKET_TYPE_DATA: new_message(P, (const uint8_t *)smsg->buffer, smsg->ud); skynet_free(smsg->buffer); response(ctx, P); break; case SKYNET_SOCKET_TYPE_WARNING: skynet_error(ctx, "Overload on %d", P->fd); break; default: // ignore break; } }
//初始化某个snlua服务,snlua在create时创建了一个lua虚拟机 //l, 服务实例 //ctx,与服务实例关联的一些上下文配置资源 //args,参数{通常为脚本名} int snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) { //复制参数 int sz = strlen(args); char * tmp = skynet_malloc(sz); memcpy(tmp, args, sz); //设置启动回调 skynet_callback(ctx, l , launch_cb); //注册一个服务名称,如果没用字符串,直接返回16进制格式返回服务":唯一ID" //否则注册一个字符串格式的名字 const char * self = skynet_command(ctx, "REG", NULL); uint32_t handle_id = strtoul(self+1, NULL, 16); // it must be first message //由框架向目标服务handle_id投递一个消息,必须保证这是服务的接收的第一条消息, 消息的内容是调用参数{脚本名,session设置为0表示不需要回应} skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz); return 0; }
static void report_info(struct skynet_context *ctx, struct package *P, int session, uint32_t source) { int uncomplete; int uncomplete_sz; if (P->header_sz != 0) { uncomplete = -1; uncomplete_sz = 0; } else if (P->uncomplete_sz == 0) { uncomplete = 0; uncomplete_sz = 0; } else { uncomplete = P->uncomplete_sz; uncomplete_sz = P->uncomplete.sz; } char tmp[128]; int n = sprintf(tmp,"req=%d resp=%d uncomplete=%d/%d", queue_size(&P->request), queue_size(&P->response),uncomplete,uncomplete_sz); skynet_send(ctx, 0, source, PTYPE_RESPONSE, session, tmp, n); }
static void _del(struct connection_server * server, int fd) { int i; for (i=0;i<server->max_connection;i++) { struct connection * c = &server->conn[i]; if (c->fd == fd) { if (c->close == 0) { skynet_send(server->ctx, 0, c->address, PTYPE_CLIENT | PTYPE_TAG_DONTCOPY, 0, NULL, 0); connection_del(server->pool, fd); } c->address = 0; c->fd = 0; c->close = 0; close(fd); return; } } skynet_error(server->ctx, "[connection] Delete invalid handle %d", fd); }
static int _cb(struct skynet_context * context, void * ud, int session, uint32_t source, const void * msg, size_t sz) { struct broker * b = ud; if (b->init < DEFAULT_NUMBER) { if (source != b->launcher) return 0; char addr[sz+1]; memcpy(addr, msg, sz); addr[sz] = '\0'; uint32_t address = strtoul(addr+1, NULL, 16); assert(address != 0); _init(b, session, address); if (b->init == DEFAULT_NUMBER) { skynet_command(context, "REG", b->name); skynet_send(context, 0, b->launcher, 0, NULL, 0, 0); } } else { _forward(b, context); } return 0; }
static int _mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) { struct harbor * h = ud; switch (type) { case PTYPE_HARBOR: { // remote message in const char * cookie = msg; cookie += sz - 12; struct remote_message_header header; _message_to_header((const uint32_t *)cookie, &header); if (header.source == 0) { if (header.destination < REMOTE_MAX) { // 1 byte harbor id (0~255) // update remote harbor address char ip [sz - 11]; memcpy(ip, msg, sz-12); ip[sz-11] = '\0'; _update_remote_address(context, h, header.destination, ip); } else { // update global name if (sz - 12 > GLOBALNAME_LENGTH) { char name[sz-11]; memcpy(name, msg, sz-12); name[sz-11] = '\0'; skynet_error(context, "Global name is too long %s", name); } _update_remote_name(h, context, msg, header.destination); } } else { uint32_t destination = header.destination; int type = (destination >> HANDLE_REMOTE_SHIFT) | PTYPE_TAG_DONTCOPY; destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT); skynet_send(context, header.source, destination, type, (int)header.session, (void *)msg, sz-12); return 1; } return 0; } case PTYPE_SYSTEM: { // register name message const struct remote_message *rmsg = msg; assert (sz == sizeof(rmsg->destination)); _remote_register_name(h, context, rmsg->destination.name, rmsg->destination.handle); return 0; } default: { // remote message out const struct remote_message *rmsg = msg; if (rmsg->destination.handle == 0) { if (_remote_send_name(h, context, source , rmsg->destination.name, type, session, rmsg->message, rmsg->sz)) { return 0; } } else { if (_remote_send_handle(h, context, source , rmsg->destination.handle, type, session, rmsg->message, rmsg->sz)) { return 0; } } free((void *)rmsg->message); return 0; } } }
/* unsigned address string address integer type integer session string message lightuserdata message_ptr integer len */ static int _send(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); int addr_type = lua_type(L,1); uint32_t dest = 0; switch(addr_type) { case LUA_TNUMBER: dest = lua_tounsigned(L,1); break; case LUA_TSTRING: { const char * addrname = lua_tostring(L,1); if (addrname[0] == '.' || addrname[0] == ':') { dest = skynet_queryname(context, addrname); if (dest == 0) { luaL_error(L, "Invalid name %s", addrname); } } else if ('0' <= addrname[0] && addrname[0] <= '9') { luaL_error(L, "Invalid name %s: must not start with a digit", addrname); } else { return _sendname(L, context, addrname); } break; } default: return luaL_error(L, "address must be number or string, got %s",lua_typename(L,addr_type)); } int type = luaL_checkinteger(L, 2); int session = 0; if (lua_isnil(L,3)) { type |= PTYPE_TAG_ALLOCSESSION; } else { session = luaL_checkinteger(L,3); } int mtype = lua_type(L,4); switch (mtype) { case LUA_TSTRING: { size_t len = 0; void * msg = (void *)lua_tolstring(L,4,&len); if (len == 0) { msg = NULL; } session = skynet_send(context, 0, dest, type, session , msg, len); break; } case LUA_TLIGHTUSERDATA: { void * msg = lua_touserdata(L,4); int size = luaL_checkinteger(L,5); session = skynet_send(context, 0, dest, type | PTYPE_TAG_DONTCOPY, session, msg, size); break; } default: luaL_error(L, "skynet.send invalid param %s", lua_typename(L, lua_type(L,4))); } if (session < 0) { // send to invalid address // todo: maybe throw error is better return 0; } lua_pushinteger(L,session); return 1; }
static int _mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) { struct harbor * h = (struct harbor *)ud; switch (type) { case PTYPE_SOCKET: { const struct skynet_socket_message * message = (const struct skynet_socket_message *)msg; switch(message->type) { case SKYNET_SOCKET_TYPE_DATA: skynet_free(message->buffer); skynet_error(context, "recv invalid socket message (size=%d)", message->ud); break; case SKYNET_SOCKET_TYPE_ACCEPT: skynet_error(context, "recv invalid socket accept message"); break; case SKYNET_SOCKET_TYPE_ERROR: case SKYNET_SOCKET_TYPE_CLOSE: close_harbor(h, message->id); break; case SKYNET_SOCKET_TYPE_CONNECT: open_harbor(h, message->id); break; } return 0; } case PTYPE_HARBOR: { // remote message in const char * cookie = (const char *)msg; cookie += sz - 12; struct remote_message_header header; _message_to_header((const uint32_t *)cookie, &header); if (header.source == 0) { if (header.destination < REMOTE_MAX) { // 1 byte harbor id (0~255) // update remote harbor address //char ip [sz - 11]; char ip [100]; memcpy(ip, msg, sz-12); ip[sz-11] = '\0'; _update_remote_address(h, header.destination, ip); } else { // update global name if (sz - 12 > GLOBALNAME_LENGTH) { //char name[sz-11]; char name[100]; memcpy(name, msg, sz-12); name[sz-11] = '\0'; skynet_error(context, "Global name is too long %s", name); } _update_remote_name(h, (const char*)msg, header.destination); } } else { uint32_t destination = header.destination; int type = (destination >> HANDLE_REMOTE_SHIFT) | PTYPE_TAG_DONTCOPY; destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT); skynet_send(context, header.source, destination, type, (int)header.session, (void *)msg, sz-12); return 1; } return 0; } case PTYPE_SYSTEM: { // register name message const struct remote_message *rmsg = (const struct remote_message *)msg; assert (sz == sizeof(rmsg->destination)); _remote_register_name(h, rmsg->destination.name, rmsg->destination.handle); return 0; } default: { // remote message out const struct remote_message *rmsg = (const struct remote_message *)msg; if (rmsg->destination.handle == 0) { if (_remote_send_name(h, source , rmsg->destination.name, type, session, (const char*)rmsg->message, rmsg->sz)) { return 0; } } else { if (_remote_send_handle(h, source , rmsg->destination.handle, type, session, (const char *)rmsg->message, rmsg->sz)) { return 0; } } skynet_free((void *)rmsg->message); return 0; } } }