MASTER_API int master_init(struct master *m, struct skynet_context *ctx, const char * args) { //char tmp[strlen(args) + 32]; char tmp[256]; 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); m->ctx = ctx; return 0; }
static int _cb(struct skynet_context * ctx, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) { struct gate *g = ud; if (type == PTYPE_TEXT) { _ctrl(ctx, g , msg , (int)sz); return 0; } assert(type == PTYPE_RESPONSE); struct mread_pool * m = g->pool; int connection_id = mread_poll(m,100); // timeout : 100ms if (connection_id < 0) { skynet_command(ctx, "TIMEOUT", "1"); } else { int id = g->map[connection_id].uid; if (id == 0) { id = _gen_id(g, connection_id); int fd = mread_socket(m , connection_id); struct sockaddr_in remote_addr; socklen_t len = sizeof(struct sockaddr_in); getpeername(fd, (struct sockaddr *)&remote_addr, &len); _report(g, ctx, "%d open %d %s:%u",id,fd,inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port)); } uint8_t * plen = mread_pull(m,g->header_size); if (plen == NULL) { if (mread_closed(m)) { _remove_id(g,id); _report(g, ctx, "%d close", id); } goto _break; } // big-endian int len ; if (g->header_size == 2) { len = plen[0] << 8 | plen[1]; } else { len = plen[0] << 24 | plen[1] << 16 | plen[2] << 8 | plen[3]; } void * data = mread_pull(m, len); if (data == NULL) { if (mread_closed(m)) { _remove_id(g,id); _report(g, ctx, "%d close", id); } goto _break; } _forward(ctx, g, id, data, len); mread_yield(m); _break: skynet_command(ctx, "TIMEOUT", "0"); } return 0; }
int syslog_init (void *inst, struct skynet_context *ctx, const char *ident) { openlog (ident, LOG_PID, LOG_LOCAL3); skynet_callback (ctx, NULL, cb); skynet_command (ctx, "REG", ".logger"); return 0; }
int localcast_init(void * ud, struct skynet_context *ctx, const char * args) { skynet_callback(ctx, ud, _maincb); skynet_command(ctx, "REG", ".cast"); return 0; }
static void _poll(struct connection_server * server) { int timeout = 100; void * buffer = NULL; for (;;) { struct connection * c = connection_poll(server->pool, timeout); if (c==NULL) { skynet_command(server->ctx,"TIMEOUT","1"); return; } timeout = 0; if (buffer == NULL) { buffer = malloc(DEFAULT_BUFFER_SIZE); } int size = read(c->fd, buffer, DEFAULT_BUFFER_SIZE); if (size < 0) { continue; } if (size == 0) { free(buffer); buffer = NULL; if (c->close == 0) { c->close = 1; skynet_send(server->ctx, 0, c->address, PTYPE_CLIENT | PTYPE_TAG_DONTCOPY, 0, NULL, 0); connection_del(server->pool, c->fd); } } else { skynet_send(server->ctx, 0, c->address, PTYPE_CLIENT | PTYPE_TAG_DONTCOPY, 0, buffer, size); buffer = NULL; } } }
static int laddresscommand(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); const char * cmd = luaL_checkstring(L,1); const char * result; const char * parm = NULL; if (lua_gettop(L) == 2) { parm = luaL_checkstring(L,2); } result = skynet_command(context, cmd, parm); if (result && result[0] == ':') { int i; uint32_t addr = 0; for (i=1;result[i];i++) { int c = result[i]; if (c>='0' && c<='9') { c = c - '0'; } else if (c>='a' && c<='f') { c = c - 'a' + 10; } else if (c>='A' && c<='F') { c = c - 'A' + 10; } else { return 0; } addr = addr * 16 + c; } lua_pushinteger(L, addr); return 1; } return 0; }
static const char * optstring(struct skynet_context *ctx, const char *key, const char * str) { const char * ret = skynet_command(ctx, "GETENV", key); if (ret == NULL) { return str; } return ret; }
static int init_cb(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) { lua_State *L = l->L; l->ctx = ctx; lua_gc(L, LUA_GCSTOP, 0); lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); luaL_openlibs(L); lua_pushlightuserdata(L, ctx); lua_setfield(L, LUA_REGISTRYINDEX, "skynet_context"); luaL_requiref(L, "skynet.codecache", codecache , 0); lua_pop(L,1); const char *path = optstring(ctx, "lua_path","./lualib/?.lua;./lualib/?/init.lua"); lua_pushstring(L, path); lua_setglobal(L, "LUA_PATH"); const char *cpath = optstring(ctx, "lua_cpath","./luaclib/?.so"); lua_pushstring(L, cpath); lua_setglobal(L, "LUA_CPATH"); const char *service = optstring(ctx, "luaservice", "./service/?.lua"); lua_pushstring(L, service); lua_setglobal(L, "LUA_SERVICE"); const char *preload = skynet_command(ctx, "GETENV", "preload"); lua_pushstring(L, preload); lua_setglobal(L, "LUA_PRELOAD"); lua_pushcfunction(L, traceback); assert(lua_gettop(L) == 1); const char * loader = optstring(ctx, "lualoader", "./lualib/loader.lua"); int r = luaL_loadfile(L,loader); if (r != LUA_OK) { skynet_error(ctx, "Can't load %s : %s", loader, lua_tostring(L, -1)); report_launcher_error(ctx); return 1; } lua_pushlstring(L, args, sz); r = lua_pcall(L,1,0,1); if (r != LUA_OK) { skynet_error(ctx, "lua loader error : %s", lua_tostring(L, -1)); report_launcher_error(ctx); return 1; } lua_settop(L,0); if (lua_getfield(L, LUA_REGISTRYINDEX, "memlimit") == LUA_TNUMBER) { size_t limit = lua_tointeger(L, -1); l->mem_limit = limit; skynet_error(ctx, "Set memory limit to %.2f M", (float)limit / (1024 * 1024)); lua_pushnil(L); lua_setfield(L, LUA_REGISTRYINDEX, "memlimit"); } lua_pop(L, 1); lua_gc(L, LUA_GCRESTART, 0); return 0; }
static void _launch_gate(struct skynet_context * ctx, const char * local_addr) { char tmp[128]; sprintf(tmp,"gate L ! %s %d %d 0",local_addr, PTYPE_HARBOR, REMOTE_MAX); const char * gate_addr = skynet_command(ctx, "LAUNCH", tmp); if (gate_addr == NULL) { fprintf(stderr, "Harbor : launch gate failed\n"); exit(1); } uint32_t gate = strtoul(gate_addr+1 , NULL, 16); if (gate == 0) { fprintf(stderr, "Harbor : launch gate invalid %s", gate_addr); exit(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); }
int connection_init(struct connection_server * server, struct skynet_context * ctx, char * param) { server->pool = connection_newpool(DEFAULT_CONNECTION); if (server->pool == NULL) return 1; server->max_connection = strtol(param, NULL, 10); if (server->max_connection == 0) { server->max_connection = DEFAULT_CONNECTION; } server->current_connection = 0; server->ctx = ctx; server->conn = malloc(server->max_connection * sizeof(struct connection)); memset(server->conn, 0, server->max_connection * sizeof(struct connection)); skynet_callback(ctx, server, _connection_main); skynet_command(ctx,"REG",".connection"); skynet_command(ctx,"TIMEOUT","0"); return 0; }
int harbor_init(struct harbor *h, struct skynet_context *ctx, const char * args) { int sz = strlen(args)+1; char master_addr[sz]; char local_addr[sz]; int harbor_id = 0; sscanf(args,"%s %s %d",master_addr, local_addr, &harbor_id); int master_fd = _connect_to(ctx, master_addr); if (master_fd < 0) { skynet_error(ctx, "Harbor : Connect to master %s faild",master_addr); return 1; } printf("Connect to master %s\n",master_addr); h->master_addr = strdup(master_addr); h->master_fd = master_fd; char tmp[128]; sprintf(tmp,"gate L ! %s %d %d 0",local_addr, PTYPE_HARBOR, REMOTE_MAX); const char * gate_addr = skynet_command(ctx, "LAUNCH", tmp); if (gate_addr == NULL) { skynet_error(ctx, "Harbor : launch gate failed"); return 1; } uint32_t gate = strtoul(gate_addr+1 , NULL, 16); if (gate == 0) { skynet_error(ctx, "Harbor : 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); h->id = harbor_id; skynet_callback(ctx, h, _mainloop); _report_local_address(h, ctx, local_addr, harbor_id); return 0; }
static int launch_cb(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) { assert(type == 0 && session == 0); struct snlua *l = ud; skynet_callback(context, NULL, NULL); // 将消息处理函数置空,以免别的消息发过来 int err = init_cb(l, context, msg, sz); // 消息处理:通过 loader.lua 加载 lua 代码块 if (err) { skynet_command(context, "EXIT", NULL); } return 0; }
static int _launch(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) { assert(type == 0 && session == 0); struct snlua *l = ud; skynet_callback(context, NULL, NULL); int err = _init(l, context, msg, sz); if (err) { skynet_command(context, "EXIT", NULL); } return 0; }
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); const char * self = skynet_command(ctx, "REG", NULL); uint32_t handle_id = strtoul(self+1, NULL, 16); // it must be first message skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz); return 0; }
static void heartbeat(struct skynet_context *ctx, struct package *P) { if (P->recv == P->heartbeat) { if (!P->closed) { skynet_socket_shutdown(ctx, P->fd); skynet_error(ctx, "timeout %d", P->fd); } } else { P->heartbeat = P->recv = 0; skynet_command(ctx, "TIMEOUT", TIMEOUT); } }
static void _ctrl(struct skynet_context * ctx, struct gate * g, const void * msg, int sz) { char tmp[sz+1]; memcpy(tmp, msg, sz); tmp[sz] = '\0'; char * command = tmp; int i; if (sz == 0) return; for (i=0;i<sz;i++) { if (command[i]==' ') { break; } } if (memcmp(command,"kick",i)==0) { _parm(tmp, sz, i); int uid = strtol(command , NULL, 10); struct connection * agent = _id_to_agent(g,uid); if (agent) { int connection_id = agent->connection_id; mread_close_client(g->pool,connection_id); } return; } if (memcmp(command,"forward",i)==0) { _parm(tmp, sz, i); char * client = tmp; char * idstr = strsep(&client, " "); if (client == NULL) { return; } int id = strtol(idstr , NULL, 10); char * agent = strsep(&client, " "); if (client == NULL) { return; } uint32_t agent_handle = strtoul(agent+1, NULL, 16); uint32_t client_handle = strtoul(client+1, NULL, 16); _forward_agent(g, id, agent_handle, client_handle); return; } if (memcmp(command,"broker",i)==0) { _parm(tmp, sz, i); g->broker = skynet_queryname(ctx, command); return; } if (memcmp(command,"start",i) == 0) { skynet_command(ctx,"TIMEOUT","0"); return; } skynet_error(ctx, "[gate] Unkown command : %s", command); }
static void service_exit(struct skynet_context *ctx, struct package *P) { // report manager P->closed = 1; while (!queue_empty(&P->request)) { struct request req; queue_pop(&P->request, &req); skynet_send(ctx, 0, req.source, PTYPE_ERROR, req.session, NULL, 0); } // free unsend response buffer on package_release skynet_send(ctx, 0, P->manager, PTYPE_TEXT, 0, "CLOSED", 6); skynet_command(ctx, "EXIT", NULL); }
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); // 注册消息处理函数 const char * self = skynet_command(ctx, "REG", NULL); // 得到自身的服务的地址,是一个带冒号的字符串 uint32_t handle_id = strtoul(self+1, NULL, 16); // 得到数字地址 // it must be first message //直接发送消息,以便snlua能第一个加载 相应的服务 skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz); // 发消息给自己以便加载相应的服务模块 return 0; }
static int _cb(struct skynet_context * context, void * ud, int session, const char * addr, const void * msg, size_t sz) { lua_State *L = ud; int trace = 1; int top = lua_gettop(L); if (top == 1) { lua_rawgetp(L, LUA_REGISTRYINDEX, _cb); } else { assert(top == 2); lua_pushvalue(L,2); } int r; if (msg == NULL) { if (addr == NULL) { lua_pushinteger(L, session); r = lua_pcall(L, 1, 0 , trace); } else { lua_pushinteger(L, session); lua_pushstring(L, addr); r = lua_pcall(L, 2, 0 , trace); } } else { lua_pushinteger(L, session); lua_pushstring(L, addr); lua_pushlightuserdata(L,(void *)msg); lua_pushinteger(L,sz); r = lua_pcall(L, 4, 0 , trace); } if (r == LUA_OK) return 0; const char * self = skynet_command(context, "REG", NULL); switch (r) { case LUA_ERRRUN: skynet_error(context, "lua call [%s to %s : %d msgsz = %d] error : %s", addr , self, session, sz, lua_tostring(L,-1)); break; case LUA_ERRMEM: skynet_error(context, "lua memory error : [%s to %s : %d]", addr , self, session); break; case LUA_ERRERR: skynet_error(context, "lua error in error : [%s to %s : %d]", addr , self, session); break; case LUA_ERRGCMM: skynet_error(context, "lua gc error : [%s to %s : %d]", addr , self, session); break; }; lua_pop(L,1); return 0; }
static int _command(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); const char * cmd = luaL_checkstring(L,1); const char * result; const char * parm = NULL; if (lua_gettop(L) == 2) { parm = luaL_checkstring(L,2); } result = skynet_command(context, cmd, parm); if (result) { lua_pushstring(L, result); return 1; } return 0; }
static int _launch(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) { assert(type == 0 && session == 0); struct snlua *l = ud; skynet_callback(context, NULL, NULL); struct timespec ti; current_time(&ti); int err = _init(l, context, msg); double t = diff_time(&ti); lua_pushnumber(l->L, t); lua_setfield(l->L, LUA_REGISTRYINDEX, "skynet_boottime"); if (err) { skynet_command(context, "EXIT", NULL); } return 0; }
//初始化某个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 int _cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) { lua_State *L = ud; int trace = 1; int r; int top = lua_gettop(L); if (top == 0) { lua_pushcfunction(L, traceback); lua_rawgetp(L, LUA_REGISTRYINDEX, _cb); } else { assert(top == 2); } lua_pushvalue(L,2); lua_pushinteger(L, type); lua_pushlightuserdata(L, (void *)msg); lua_pushinteger(L,sz); lua_pushinteger(L, session); lua_pushnumber(L, source); r = lua_pcall(L, 5, 0 , trace); if (r == LUA_OK) { return 0; } const char * self = skynet_command(context, "REG", NULL); switch (r) { case LUA_ERRRUN: skynet_error(context, "lua call [%x to %s : %d msgsz = %d] error : " KRED "%s" KNRM, source , self, session, sz, lua_tostring(L,-1)); break; case LUA_ERRMEM: skynet_error(context, "lua memory error : [%x to %s : %d]", source , self, session); break; case LUA_ERRERR: skynet_error(context, "lua error in error : [%x to %s : %d]", source , self, session); break; case LUA_ERRGCMM: skynet_error(context, "lua gc error : [%x to %s : %d]", source , self, session); break; }; lua_pop(L,1); return 0; }
LOGGER_API int logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm) { if (parm) { inst->handle = fopen(parm,"w"); if (inst->handle == NULL) { return 1; } inst->close = 1; } else { inst->handle = stdout; } if (inst->handle) { skynet_callback(ctx, inst, _logger); skynet_command(ctx, "REG", ".logger"); return 0; } return 1; }
void skynet_start(struct skynet_config * config) { skynet_group_init(); skynet_harbor_init(config->harbor); skynet_handle_init(config->harbor); skynet_mq_init(); skynet_module_init(config->module_path); skynet_timer_init(); skynet_socket_init(); if (config->standalone) { if (_start_master(config->standalone)) { fprintf(stderr, "Init fail : mater"); return; } } // harbor must be init first if (skynet_harbor_start(config->master , config->local)) { fprintf(stderr, "Init fail : no master"); return; } struct skynet_context *ctx; ctx = skynet_context_new("logger", config->logger); if (ctx == NULL) { fprintf(stderr,"launch logger error"); exit(1); } ctx = skynet_context_new("localcast", NULL); if (ctx == NULL) { fprintf(stderr,"launch local cast error"); exit(1); } ctx = skynet_context_new("snlua", "launcher"); if (ctx) { skynet_command(ctx, "REG", ".launcher"); ctx = skynet_context_new("snlua", config->start); } _start(config->thread); skynet_socket_free(); }
int logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm) { if (parm) { inst->handle = fopen(parm,"w"); if (inst->handle == NULL) { return 1; } inst->filename = skynet_malloc(strlen(parm)+1); strcpy(inst->filename, parm); inst->close = 1; } else { inst->handle = stdout; } if (inst->handle) { skynet_callback(ctx, inst, logger_cb); skynet_command(ctx, "REG", ".logger"); return 0; } return 1; }
int logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm) { if (parm) { inst->handle = fopen(parm,"w"); if (inst->handle == NULL) { return 1; } inst->close = 1; } else { inst->handle = stdout; } #ifdef _MSC_VER _wsetlocale(0, L"chs"); #endif if (inst->handle) { skynet_callback(ctx, inst, _logger); skynet_command(ctx, "REG", ".logger"); return 0; } return 1; }
// 多播的主要处理函数 static int _maincb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) { struct skynet_multicast_group *g = ud; // PTYPE_SYSTEM 协议控制命令 if (type == PTYPE_SYSTEM) { char cmd = '\0'; uint32_t handle = 0; sscanf(msg,"%c %x",&cmd,&handle); // 格式化参数 if (handle == 0) { skynet_error(context, "Invalid handle %s",msg); return 0; } // 简单的命令协议 switch (cmd) { case 'E': skynet_multicast_entergroup(g, handle); break; case 'L': skynet_multicast_leavegroup(g, handle); break; case 'C': skynet_command(context, "EXIT", NULL); break; default: skynet_error(context, "Invalid command %s",msg); break; } return 0; } // 发送消息出去 else { sz |= type << HANDLE_REMOTE_SHIFT; struct skynet_multicast_message * mc = skynet_multicast_create(msg, sz, source); skynet_multicast_castgroup(context, g, mc); return 1; } }
static int _load(lua_State *L, char ** filename) { const char * name = strsep(filename, " \r\n"); const char * path = skynet_command(NULL, "GETENV", "luaservice"); while (path[0]) { int pathlen; char * pathend = strchr(path,';'); if (pathend) { pathlen = pathend - path; } else { pathlen = strlen(path); } int r = _try_load(L, path, pathlen, name); if (r >=0) { return r; } path+=pathlen; if (path[0]==';') ++path; } return -1; }
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; }