int fiber_channel_check_wait(struct fiber_channel *ch, ev_tstamp start_time, ev_tstamp timeout) { /* * Preconditions of waiting are: * - the channel is not closed, * - the current fiber has not been * cancelled, * - the timeout has not expired. * If timeout is non-zero, yield at least once, otherwise * rounding errors can lead to an infinite loop in the * caller, since ev_now() does not get updated without * a yield. */ if (ch->is_closed) { diag_set(ChannelIsClosed); return -1; } if (fiber_is_cancelled()) { diag_set(FiberIsCancelled); return -1; } if (timeout == 0 || ev_monotonic_now(loop()) > start_time + timeout) { diag_set(TimedOut); return -1; } return 0; }
static int memtx_bitset_index_register_tuple(struct memtx_bitset_index *index, struct tuple *tuple) { uint32_t id; struct tuple **place; if (index->spare_id != SPARE_ID_END) { id = index->spare_id; void *mem = matras_get(index->id_to_tuple, id); index->spare_id = *(uint32_t *)mem; place = (struct tuple **)mem; } else { place = (struct tuple **)matras_alloc(index->id_to_tuple, &id); } *place = tuple; struct bitset_hash_entry entry; entry.id = id; entry.tuple = tuple; uint32_t pos = mh_bitset_index_put(index->tuple_to_id, &entry, 0, 0); if (pos == mh_end(index->tuple_to_id)) { *(uint32_t *)tuple = index->spare_id; index->spare_id = id; diag_set(OutOfMemory, (ssize_t) pos, "hash", "key"); return -1; } return 0; }
/** * Populate key options from their msgpack-encoded representation * (msgpack map). */ int opts_decode(void *opts, const struct opt_def *reg, const char **map, uint32_t errcode, uint32_t field_no, struct region *region) { assert(mp_typeof(**map) == MP_MAP); /* * The implementation below has O(map_size * reg_size) complexity. * DDL is not performance-critical, so this is not a problem. */ uint32_t map_size = mp_decode_map(map); for (uint32_t i = 0; i < map_size; i++) { if (mp_typeof(**map) != MP_STR) { diag_set(ClientError, errcode, field_no, "key must be a string"); return -1; } uint32_t key_len; const char *key = mp_decode_str(map, &key_len); if (opts_parse_key(opts, reg, key, key_len, map, errcode, field_no, region, false) != 0) return -1; } return 0; }
int main(int argc, const char *argv[]) { const char **arg1; #if 0 unsigned int n = 1024; /* this is default on my Linux */ #endif diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); arg1 = argv+1; --argc; while (arg1[0] && (arg1[0][0] == '-')) { switch (arg1[0][1]) { #if WITH_HELP case '?': case 'h': procan_usage(stdout); exit(0); #endif /* WITH_HELP */ case 'c': procan_cdefs(stdout); exit(0); #if LATER case 'V': procan_version(stdout); exit(0); case 'l': diag_set(arg1[0][2], &arg1[0][3]); break; case 'd': diag_set('d', NULL); break; #endif #if 0 case 'n': n = strtoul(&arg1[0][2], NULL, 0); break; #endif case '\0': break; default: diag_set_int('e', E_FATAL); Error1("unknown option \"%s\"", arg1[0]); #if WITH_HELP procan_usage(stderr); #endif exit(1); } if (arg1[0][1] == '\0') break; ++arg1; --argc; } if (argc != 0) { Error1("%d superfluous arguments", argc); #if WITH_HELP procan_usage(stderr); #endif exit(1); } procan(stdout); hostan(stdout); return 0; }
static int blackhole_space_execute_upsert(struct space *space, struct txn *txn, struct request *request) { (void)space; (void)txn; (void)request; diag_set(ClientError, ER_UNSUPPORTED, "Blackhole", "upsert()"); return -1; }
static int blackhole_space_execute_delete(struct space *space, struct txn *txn, struct request *request, struct tuple **result) { (void)space; (void)txn; (void)request; (void)result; diag_set(ClientError, ER_UNSUPPORTED, "Blackhole", "delete()"); return -1; }
/** * Open file descriptor and lock it. */ int path_lock(const char *path, int *lock) { int fd = open(path, O_RDONLY); if (fd < 0) { diag_set(SystemError, "Can't open path: %s", path); return -1; } if (flock(fd, LOCK_EX | LOCK_NB) < 0) { if (errno != EWOULDBLOCK) { diag_set(SystemError, "Can't lock path: %s", path); close(fd); return -1; } close(fd); fd = -1; } *lock= fd; return 0; }
void luamp_encode_tuple(struct lua_State *L, struct luaL_serializer *cfg, struct mpstream *stream, int index) { struct tuple *tuple = luaT_istuple(L, index); if (tuple != NULL) { return tuple_to_mpstream(tuple, stream); } else if (luamp_encode(L, cfg, stream, index) != MP_ARRAY) { diag_set(ClientError, ER_TUPLE_NOT_ARRAY); luaT_error(L); } }
struct fiber_channel * fiber_channel_new(uint32_t size) { struct fiber_channel *res = (struct fiber_channel *) malloc(fiber_channel_memsize(size)); if (res == NULL) { diag_set(OutOfMemory, size, "malloc", "struct fiber_channel"); return NULL; } fiber_channel_create(res, size); return res; }
static inline int lbox_catch(lua_State *L) { struct error *e = luaL_iserror(L, -1); if (e != NULL) { /* Re-throw original error */ diag_add_error(&fiber()->diag, e); } else { /* Convert Lua error to a Tarantool exception. */ diag_set(LuajitError, lua_tostring(L, -1)); } return 1; }
struct engine * blackhole_engine_new(void) { struct engine *engine = calloc(1, sizeof(*engine)); if (engine == NULL) { diag_set(OutOfMemory, sizeof(*engine), "malloc", "struct engine"); return NULL; } engine->vtab = &blackhole_engine_vtab; engine->name = "blackhole"; engine->flags = ENGINE_BYPASS_TX; return engine; }
static struct space * blackhole_engine_create_space(struct engine *engine, struct space_def *def, struct rlist *key_list) { if (!rlist_empty(key_list)) { diag_set(ClientError, ER_UNSUPPORTED, "Blackhole", "indexes"); return NULL; } struct space *space = (struct space *)calloc(1, sizeof(*space)); if (space == NULL) { diag_set(OutOfMemory, sizeof(*space), "malloc", "struct space"); return NULL; } /* Allocate tuples on runtime arena, but check space format. */ struct tuple_format *format; format = tuple_format_new(&tuple_format_runtime->vtab, NULL, NULL, 0, def->fields, def->field_count, def->exact_field_count, def->dict, false, false); if (format == NULL) { free(space); return NULL; } tuple_format_ref(format); if (space_create(space, engine, &blackhole_space_vtab, def, key_list, format) != 0) { tuple_format_unref(format); free(space); return NULL; } return space; }
static int execute_lua_eval(lua_State *L) { struct lua_function_ctx *ctx = (struct lua_function_ctx *) lua_topointer(L, 1); struct request *request = ctx->request; struct obuf *out = ctx->out; struct obuf_svp *svp = &ctx->svp; lua_settop(L, 0); /* clear the stack to simplify the logic below */ /* Compile expression */ const char *expr = request->key; uint32_t expr_len = mp_decode_strl(&expr); if (luaL_loadbuffer(L, expr, expr_len, "=eval")) { diag_set(LuajitError, lua_tostring(L, -1)); lbox_error(L); } /* Unpack arguments */ const char *args = request->tuple; uint32_t arg_count = mp_decode_array(&args); luaL_checkstack(L, arg_count, "eval: out of stack"); for (uint32_t i = 0; i < arg_count; i++) { luamp_decode(L, luaL_msgpack_default, &args); } /* Call compiled code */ lua_call(L, arg_count, LUA_MULTRET); /* Send results of the called procedure to the client. */ if (iproto_prepare_select(out, svp) != 0) diag_raise(); ctx->out_is_dirty = true; struct mpstream stream; mpstream_init(&stream, out, obuf_reserve_cb, obuf_alloc_cb, luamp_error, L); int nrets = lua_gettop(L); for (int k = 1; k <= nrets; ++k) { luamp_encode(L, luaL_msgpack_default, &stream, k); } mpstream_flush(&stream); iproto_reply_select(out, svp, request->header->sync, nrets); return 0; }
int field_map_builder_create(struct field_map_builder *builder, uint32_t minimal_field_map_size, struct region *region) { builder->extents_size = 0; builder->slot_count = minimal_field_map_size / sizeof(uint32_t); if (minimal_field_map_size == 0) { builder->slots = NULL; return 0; } uint32_t sz = builder->slot_count * sizeof(builder->slots[0]); builder->slots = region_alloc(region, sz); if (builder->slots == NULL) { diag_set(OutOfMemory, sz, "region_alloc", "field_map"); return -1; } memset((char *)builder->slots, 0, sz); builder->slots = builder->slots + builder->slot_count; return 0; }
struct field_map_builder_slot_extent * field_map_builder_slot_extent_new(struct field_map_builder *builder, int32_t offset_slot, uint32_t multikey_count, struct region *region) { struct field_map_builder_slot_extent *extent; assert(!builder->slots[offset_slot].has_extent); uint32_t sz = sizeof(struct field_map_builder_slot_extent) + multikey_count * sizeof(uint32_t); extent = region_alloc(region, sz); if (extent == NULL) { diag_set(OutOfMemory, sz, "region", "extent"); return NULL; } memset(extent, 0, sz); extent->size = multikey_count; builder->slots[offset_slot].extent = extent; builder->slots[offset_slot].has_extent = true; builder->extents_size += sz; return extent; }
struct ipc_value * ipc_value_new() { if (! mempool_is_initialized(&ipc_value_pool)) { /* * We don't need to bother with * destruction since the entire slab cache * is freed when the thread ends. */ mempool_create(&ipc_value_pool, &cord()->slabc, sizeof(struct ipc_value)); } struct ipc_value *value = (struct ipc_value *) mempool_alloc(&ipc_value_pool); if (value == NULL) { diag_set(OutOfMemory, sizeof(struct ipc_value), "ipc_msg_pool", "struct ipc_value"); return NULL; } value->base.destroy = ipc_value_delete; return value; }
int opts_parse_key(void *opts, const struct opt_def *reg, const char *key, uint32_t key_len, const char **data, uint32_t errcode, uint32_t field_no, struct region *region, bool skip_unknown_options) { for (const struct opt_def *def = reg; def->name != NULL; def++) { if (key_len != strlen(def->name) || memcmp(key, def->name, key_len) != 0) continue; return opt_set(opts, def, data, region, errcode, field_no); } if (! skip_unknown_options) { char *errmsg = tt_static_buf(); snprintf(errmsg, TT_STATIC_BUF_LEN, "unexpected option '%.*s'", key_len, key); diag_set(ClientError, errcode, field_no, errmsg); return -1; } mp_next(data); return 0; }
struct tuple * luaT_tuple_new(struct lua_State *L, int idx, box_tuple_format_t *format) { if (idx != 0 && !lua_istable(L, idx) && !luaT_istuple(L, idx)) { diag_set(IllegalParams, "A tuple or a table expected, got %s", lua_typename(L, lua_type(L, idx))); return NULL; } struct ibuf *buf = tarantool_lua_ibuf; ibuf_reset(buf); struct mpstream stream; mpstream_init(&stream, buf, ibuf_reserve_cb, ibuf_alloc_cb, luamp_error, L); if (idx == 0) { /* * Create the tuple from lua stack * objects. */ int argc = lua_gettop(L); mpstream_encode_array(&stream, argc); for (int k = 1; k <= argc; ++k) { luamp_encode(L, luaL_msgpack_default, &stream, k); } } else { /* Create the tuple from a Lua table. */ luamp_encode_tuple(L, &tuple_serializer, &stream, idx); } mpstream_flush(&stream); struct tuple *tuple = box_tuple_new(format, buf->buf, buf->buf + ibuf_used(buf)); if (tuple == NULL) return NULL; ibuf_reinit(tarantool_lua_ibuf); return tuple; }
/* we expect the form "host:port" */ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int socktype, int ipproto, int pf) { struct single *xfd = &xxfd->stream; struct opt *opts0 = NULL; const char *hostname = argv[1], *portname = argv[2]; bool dofork = false; union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union them_sa, *them = &them_sa; socklen_t uslen = sizeof(us_sa); socklen_t themlen = sizeof(them_sa); bool needbind = false; bool lowport = false; int level; int result; if (argc != 3) { Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1); } xfd->howtoend = END_SHUTDOWN; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); retropt_bool(opts, OPT_FORK, &dofork); if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], them, &themlen, us, &uslen, &needbind, &lowport, socktype) != STAT_OK) { return STAT_NORETRY; } if (dofork) { xiosetchilddied(); /* set SIGCHLD handler */ } if (xioopts.logopt == 'm') { Info("starting connect loop, switching to syslog"); diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; } else { Info("starting connect loop"); } do { /* loop over retries and forks */ #if WITH_RETRY if (xfd->forever || xfd->retry) { level = E_INFO; } else #endif /* WITH_RETRY */ level = E_ERROR; result = _xioopen_connect(xfd, needbind?(struct sockaddr *)us:NULL, uslen, (struct sockaddr *)them, themlen, opts, pf, socktype, ipproto, lowport, level); switch (result) { case STAT_OK: break; #if WITH_RETRY case STAT_RETRYLATER: case STAT_RETRYNOW: if (xfd->forever || xfd->retry) { --xfd->retry; if (result == STAT_RETRYLATER) { Nanosleep(&xfd->intervall, NULL); } dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL); continue; } return STAT_NORETRY; #endif /* WITH_RETRY */ default: free(opts0);free(opts); return result; } #if WITH_RETRY if (dofork) { pid_t pid; int level = E_ERROR; if (xfd->forever || xfd->retry) { level = E_WARN; /* most users won't expect a problem here, so Notice is too weak */ } while ((pid = xio_fork(false, level)) < 0) { if (xfd->forever || --xfd->retry) { Nanosleep(&xfd->intervall, NULL); continue; } free(opts0); return STAT_RETRYLATER; } if (pid == 0) { /* child process */ xfd->forever = false; xfd->retry = 0; break; } /* parent process */ Close(xfd->fd); /* with and without retry */ Nanosleep(&xfd->intervall, NULL); dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL); continue; /* with next socket() bind() connect() */ } else #endif /* WITH_RETRY */ { break; } } while (true); /* only "active" process breaks (master without fork, or child) */ if ((result = _xio_openlate(xfd, opts)) < 0) { free(opts0);free(opts); return result; } free(opts0);free(opts); return 0; }
/* creates the listening socket, bind, applies options; waits for incoming connection, checks its source address and port. Depending on fork option, it may fork a subprocess. pf specifies the syntax expected for range option. In the case of generic socket it is 0 (expecting raw binary data), and the real pf can be obtained from us->af_family; for other socket types pf == us->af_family Returns 0 if a connection was accepted; with fork option, this is always in a subprocess! Other return values indicate a problem; this can happen in the master process or in a subprocess. This function does not retry. If you need retries, handle this in a loop in the calling function (and always provide the options...) After fork, we set the forever/retry of the child process to 0 applies and consumes the following option: PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_BACKLOG, OPT_RANGE, tcpwrap, OPT_SOURCEPORT, OPT_LOWPORT, cloexec */ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, struct opt *opts, int pf, int socktype, int proto, int level) { struct sockaddr sa; socklen_t salen; int backlog = 5; /* why? 1 seems to cause problems under some load */ char *rangename; bool dofork = false; int maxchildren = 0; char infobuff[256]; char lisname[256]; union sockaddr_union _peername; union sockaddr_union _sockname; union sockaddr_union *pa = &_peername; /* peer address */ union sockaddr_union *la = &_sockname; /* local address */ socklen_t pas = sizeof(_peername); /* peer address size */ socklen_t las = sizeof(_sockname); /* local address size */ int result; retropt_bool(opts, OPT_FORK, &dofork); if (dofork) { if (!(xioflags & XIO_MAYFORK)) { Error("option fork not allowed here"); return STAT_NORETRY; } xfd->flags |= XIO_DOESFORK; } retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren); if (! dofork && maxchildren) { Error("option max-children not allowed without option fork"); return STAT_NORETRY; } if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (dofork) { xiosetchilddied(); /* set SIGCHLD handler */ } if ((xfd->fd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) { return STAT_RETRYLATER; } applyopts_cloexec(xfd->fd, opts); applyopts(xfd->fd, opts, PH_PREBIND); applyopts(xfd->fd, opts, PH_BIND); if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); Close(xfd->fd); return STAT_RETRYLATER; } #if WITH_UNIX if (us->sa_family == AF_UNIX) { applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); } #endif /* under some circumstances (e.g., TCP listen on port 0) bind() fills empty fields that we want to know. */ salen = sizeof(sa); if (Getsockname(xfd->fd, us, &uslen) < 0) { Warn4("getsockname(%d, %p, {%d}): %s", xfd->fd, &us, uslen, strerror(errno)); } applyopts(xfd->fd, opts, PH_PASTBIND); #if WITH_UNIX if (us->sa_family == AF_UNIX) { /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); } #endif /* WITH_UNIX */ #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { free(rangename); return STAT_NORETRY; } free(rangename); xfd->para.socket.dorange = true; } #endif #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP xio_retropt_tcpwrap(xfd, opts); #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ #if WITH_TCP || WITH_UDP if (retropt_ushort(opts, OPT_SOURCEPORT, &xfd->para.socket.ip.sourceport) >= 0) { xfd->para.socket.ip.dosourceport = true; } retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport); #endif /* WITH_TCP || WITH_UDP */ applyopts(xfd->fd, opts, PH_PRELISTEN); retropt_int(opts, OPT_BACKLOG, &backlog); if (Listen(xfd->fd, backlog) < 0) { Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno)); return STAT_RETRYLATER; } if (xioopts.logopt == 'm') { Info("starting accept loop, switching to syslog"); diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; } else { Info("starting accept loop"); } while (true) { /* but we only loop if fork option is set */ char peername[256]; char sockname[256]; int ps; /* peer socket */ pa = &_peername; la = &_sockname; salen = sizeof(struct sockaddr); do { /*? int level = E_ERROR;*/ Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen); if (ps >= 0) { /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/ break; /* success, break out of loop */ } if (errno == EINTR) { continue; } if (errno == ECONNABORTED) { Notice4("accept(%d, %p, {"F_socklen"}): %s", xfd->fd, &sa, salen, strerror(errno)); continue; } Msg4(level, "accept(%d, %p, {"F_socklen"}): %s", xfd->fd, &sa, salen, strerror(errno)); Close(xfd->fd); return STAT_RETRYLATER; } while (true); applyopts_cloexec(ps, opts); if (Getpeername(ps, &pa->soa, &pas) < 0) { Warn4("getpeername(%d, %p, {"F_socklen"}): %s", ps, pa, pas, strerror(errno)); pa = NULL; } if (Getsockname(ps, &la->soa, &las) < 0) { Warn4("getsockname(%d, %p, {"F_socklen"}): %s", ps, la, las, strerror(errno)); la = NULL; } Notice2("accepting connection from %s on %s", pa? sockaddr_info(&pa->soa, pas, peername, sizeof(peername)):"NULL", la? sockaddr_info(&la->soa, las, sockname, sizeof(sockname)):"NULL"); if (pa != NULL && la != NULL && xiocheckpeer(xfd, pa, la) < 0) { if (Shutdown(ps, 2) < 0) { Info2("shutdown(%d, 2): %s", ps, strerror(errno)); } Close(ps); continue; } if (pa != NULL) Info1("permitting connection from %s", sockaddr_info((struct sockaddr *)pa, pas, infobuff, sizeof(infobuff))); if (dofork) { pid_t pid; /* mostly int; only used with fork */ sigset_t mask_sigchld; /* we must prevent that the current packet triggers another fork; therefore we wait for a signal from the recent child: USR1 indicates that is has consumed the last packet; CHLD means it has terminated */ /* block SIGCHLD and SIGUSR1 until parent is ready to react */ sigemptyset(&mask_sigchld); sigaddset(&mask_sigchld, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask_sigchld, NULL); if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) { Close(xfd->fd); Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); return STAT_RETRYLATER; } if (pid == 0) { /* child */ pid_t cpid = Getpid(); Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); Info1("just born: child process "F_pid, cpid); xiosetenvulong("PID", cpid, 1); if (Close(xfd->fd) < 0) { Info2("close(%d): %s", xfd->fd, strerror(errno)); } xfd->fd = ps; #if WITH_RETRY /* !? */ xfd->forever = false; xfd->retry = 0; level = E_ERROR; #endif /* WITH_RETRY */ break; } /* server: continue loop with listen */ /* shutdown() closes the socket even for the child process, but close() does what we want */ if (Close(ps) < 0) { Info2("close(%d): %s", ps, strerror(errno)); } /* now we are ready to handle signals */ Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); while (maxchildren) { if (num_child < maxchildren) break; Notice("maxchildren are active, waiting"); /* UINT_MAX would even be nicer, but Openindiana works only with 31 bits */ while (!Sleep(INT_MAX)) ; /* any signal lets us continue */ } Info("still listening"); } else { if (Close(xfd->fd) < 0) { Info2("close(%d): %s", xfd->fd, strerror(errno)); } xfd->fd = ps; break; } } applyopts(xfd->fd, opts, PH_FD); applyopts(xfd->fd, opts, PH_PASTSOCKET); applyopts(xfd->fd, opts, PH_CONNECTED); if ((result = _xio_openlate(xfd, opts)) < 0) return result; /* set the env vars describing the local and remote sockets */ if (la != NULL) xiosetsockaddrenv("SOCK", la, las, proto); if (pa != NULL) xiosetsockaddrenv("PEER", pa, pas, proto); return 0; }
int fiber_channel_put_msg_timeout(struct fiber_channel *ch, struct ipc_msg *msg, ev_tstamp timeout) { /** Ensure delivery fairness in case of prolonged wait. */ bool first_try = true; ev_tstamp start_time = ev_monotonic_now(loop()); while (true) { /* * Check if there is a ready reader first, and * only if there is no reader try to put a message * into the channel buffer. */ if (fiber_channel_has_readers(ch)) { /** * There is a reader, push the message * immediately. */ /* * There can be no reader if there is * a buffered message or the channel is * closed. */ assert(ch->count == 0); assert(ch->is_closed == false); struct fiber *f = rlist_first_entry(&ch->waiters, struct fiber, state); /* Place the message on the pad. */ f->wait_pad->msg = msg; fiber_channel_waiter_wakeup(f, FIBER_CHANNEL_WAIT_DONE); return 0; } if (ch->count < ch->size) { /* * No reader, but the channel is buffered. * Nice, drop the message in the buffer. */ /* * Closed channels, are, well, closed, * even if there is space in the buffer. */ if (ch->is_closed) { diag_set(ChannelIsClosed); return -1; } fiber_channel_buffer_push(ch, msg); return 0; } /** * No reader and no space in the buffer. * Have to wait. */ struct fiber *f = fiber(); if (fiber_channel_check_wait(ch, start_time, timeout)) return -1; /* Prepare a wait pad. */ struct ipc_wait_pad pad; pad.status = FIBER_CHANNEL_WAIT_WRITER; pad.msg = msg; f->wait_pad = &pad; if (first_try) { rlist_add_tail_entry(&ch->waiters, f, state); first_try = false; } else { rlist_add_entry(&ch->waiters, f, state); } fiber_yield_timeout(timeout); /* * In case of yield timeout, fiber->state * is in the ch->waiters list, remove. * rlist_del_entry() is a no-op if already done. */ rlist_del_entry(f, state); f->wait_pad = NULL; if (pad.status == FIBER_CHANNEL_WAIT_CLOSED) { /* * The channel is closed. Do not touch * the channel object. It might be gone * already. */ diag_set(ChannelIsClosed); return -1; } if (pad.status == FIBER_CHANNEL_WAIT_DONE) return 0; /* OK, someone took the message. */ timeout -= ev_monotonic_now(loop()) - start_time; } }
static int opt_set(void *opts, const struct opt_def *def, const char **val, struct region *region, uint32_t errcode, uint32_t field_no) { int64_t ival; uint64_t uval; char *errmsg = tt_static_buf(); double dval; uint32_t str_len; const char *str; char *ptr; char *opt = ((char *) opts) + def->offset; switch (def->type) { case OPT_BOOL: if (mp_typeof(**val) != MP_BOOL) goto type_mismatch_err; store_bool(opt, mp_decode_bool(val)); break; case OPT_UINT32: if (mp_typeof(**val) != MP_UINT) goto type_mismatch_err; uval = mp_decode_uint(val); if (uval > UINT32_MAX) goto type_mismatch_err; store_u32(opt, uval); break; case OPT_INT64: if (mp_read_int64(val, &ival) != 0) goto type_mismatch_err; store_u64(opt, ival); break; case OPT_FLOAT: if (mp_read_double(val, &dval) != 0) goto type_mismatch_err; store_double(opt, dval); break; case OPT_STR: if (mp_typeof(**val) != MP_STR) goto type_mismatch_err; str = mp_decode_str(val, &str_len); str_len = MIN(str_len, def->len - 1); memcpy(opt, str, str_len); opt[str_len] = '\0'; break; case OPT_STRPTR: if (mp_typeof(**val) != MP_STR) goto type_mismatch_err; str = mp_decode_str(val, &str_len); if (str_len > 0) { ptr = (char *) region_alloc(region, str_len + 1); if (ptr == NULL) { diag_set(OutOfMemory, str_len + 1, "region", "opt string"); return -1; } memcpy(ptr, str, str_len); ptr[str_len] = '\0'; assert (strlen(ptr) == str_len); } else { ptr = NULL; } *(const char **)opt = ptr; break; case OPT_ENUM: if (mp_typeof(**val) != MP_STR) goto type_mismatch_err; str = mp_decode_str(val, &str_len); if (def->to_enum == NULL) { ival = strnindex(def->enum_strs, str, str_len, def->enum_max); } else { ival = def->to_enum(str, str_len); } switch(def->enum_size) { case sizeof(uint8_t): store_u8(opt, (uint8_t)ival); break; case sizeof(uint16_t): store_u16(opt, (uint16_t)ival); break; case sizeof(uint32_t): store_u32(opt, (uint32_t)ival); break; case sizeof(uint64_t): store_u64(opt, (uint64_t)ival); break; default: unreachable(); }; break; case OPT_ARRAY: if (mp_typeof(**val) != MP_ARRAY) goto type_mismatch_err; ival = mp_decode_array(val); assert(def->to_array != NULL); if (def->to_array(val, ival, opt, errcode, field_no) != 0) return -1; break; case OPT_LEGACY: mp_next(val); break; default: unreachable(); } return 0; type_mismatch_err: snprintf(errmsg, TT_STATIC_BUF_LEN, "'%s' must be %s", def->name, opt_type_strs[def->type]); diag_set(ClientError, errcode, field_no, errmsg); return -1; }
int fiber_channel_get_msg_timeout(struct fiber_channel *ch, struct ipc_msg **msg, ev_tstamp timeout) { /** Ensure delivery fairness in case of prolonged wait. */ bool first_try = true; ev_tstamp start_time = ev_monotonic_now(loop()); while (true) { struct fiber *f; /* * Buffered messages take priority over waiting * fibers, if any, since they arrived earlier. * Try to take a message from the buffer first. */ if (ch->count > 0) { /** * There can't be any buffered stuff in * a closed channel - everything is * destroyed at close. */ assert(ch->is_closed == false); *msg = fiber_channel_buffer_pop(ch); if (fiber_channel_has_writers(ch)) { /* * Move a waiting writer, if any, * from the wait list to the tail * the buffer, to preserve fairness * in message delivery order. */ f = rlist_first_entry(&ch->waiters, struct fiber, state); fiber_channel_buffer_push(ch, f->wait_pad->msg); fiber_channel_waiter_wakeup(f, FIBER_CHANNEL_WAIT_DONE); } return 0; } if (fiber_channel_has_writers(ch)) { /** * There is no buffered messages, *but* * there is a writer. This is only * possible when the channel is * unbuffered. * Take the message directly from the * writer and be done with it. */ assert(ch->size == 0); f = rlist_first_entry(&ch->waiters, struct fiber, state); *msg = f->wait_pad->msg; fiber_channel_waiter_wakeup(f, FIBER_CHANNEL_WAIT_DONE); return 0; } if (fiber_channel_check_wait(ch, start_time, timeout)) return -1; f = fiber(); /** * No reader and no space in the buffer. * Have to wait. */ struct ipc_wait_pad pad; pad.status = FIBER_CHANNEL_WAIT_READER; f->wait_pad = &pad; if (first_try) { rlist_add_tail_entry(&ch->waiters, f, state); first_try = false; } else { rlist_add_entry(&ch->waiters, f, state); } fiber_yield_timeout(timeout); /* * In case of yield timeout, fiber->state * is in the ch->waiters list, remove. * rlist_del_entry() is a no-op if already done. */ rlist_del_entry(f, state); f->wait_pad = NULL; if (pad.status == FIBER_CHANNEL_WAIT_CLOSED) { diag_set(ChannelIsClosed); return -1; } if (pad.status == FIBER_CHANNEL_WAIT_DONE) { *msg = pad.msg; return 0; } timeout -= ev_monotonic_now(loop()) - start_time; }
/** * A helper to find a Lua function by name and put it * on top of the stack. */ static int box_lua_find(lua_State *L, const char *name, const char *name_end) { int index = LUA_GLOBALSINDEX; int objstack = 0; const char *start = name, *end; while ((end = (const char *) memchr(start, '.', name_end - start))) { lua_checkstack(L, 3); lua_pushlstring(L, start, end - start); lua_gettable(L, index); if (! lua_istable(L, -1)) { diag_set(ClientError, ER_NO_SUCH_PROC, name_end - name, name); lbox_error(L); } start = end + 1; /* next piece of a.b.c */ index = lua_gettop(L); /* top of the stack */ } /* box.something:method */ if ((end = (const char *) memchr(start, ':', name_end - start))) { lua_checkstack(L, 3); lua_pushlstring(L, start, end - start); lua_gettable(L, index); if (! (lua_istable(L, -1) || lua_islightuserdata(L, -1) || lua_isuserdata(L, -1) )) { diag_set(ClientError, ER_NO_SUCH_PROC, name_end - name, name); lbox_error(L); } start = end + 1; /* next piece of a.b.c */ index = lua_gettop(L); /* top of the stack */ objstack = index; } lua_pushlstring(L, start, name_end - start); lua_gettable(L, index); if (!lua_isfunction(L, -1) && !lua_istable(L, -1)) { /* lua_call or lua_gettable would raise a type error * for us, but our own message is more verbose. */ diag_set(ClientError, ER_NO_SUCH_PROC, name_end - name, name); lbox_error(L); } /* setting stack that it would contain only * the function pointer. */ if (index != LUA_GLOBALSINDEX) { if (objstack == 0) { /* no object, only a function */ lua_replace(L, 1); } else if (objstack == 1) { /* just two values, swap them */ lua_insert(L, -2); } else { /* long path */ lua_insert(L, 1); lua_insert(L, 2); objstack = 1; } lua_settop(L, 1 + objstack); } return 1 + objstack; }
int main(int argc, const char *argv[]) { const char **arg1, *a; char *mainwaitstring; char buff[10]; double rto; int i, argc0, result; struct utsname ubuf; int lockrc; if (mainwaitstring = getenv("SOCAT_MAIN_WAIT")) { sleep(atoi(mainwaitstring)); } diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); /* we must init before applying options because env settings have lower priority and are to be overridden by options */ if (xioinitialize(XIO_MAYALL) != 0) { Exit(1); } xiosetopt('p', "%"); xiosetopt('o', ":"); argc0 = argc; /* save for later use */ arg1 = argv+1; --argc; while (arg1[0] && (arg1[0][0] == '-')) { switch (arg1[0][1]) { case 'V': socat_version(stdout); Exit(0); #if WITH_HELP case '?': case 'h': socat_usage(stdout); xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0); Exit(0); #endif /* WITH_HELP */ case 'd': diag_set('d', NULL); break; #if WITH_FILAN case 'D': xioparams->debug = true; break; #endif case 'l': switch (arg1[0][2]) { case 'm': /* mixed mode: stderr, then switch to syslog; + facility */ diag_set('s', NULL); xiosetopt('l', "m"); xioparams->logopt = arg1[0][2]; xiosetopt('y', &arg1[0][3]); break; case 'y': /* syslog + facility */ diag_set(arg1[0][2], &arg1[0][3]); break; case 'f': /* to file, +filename */ case 'p': /* artificial program name */ if (arg1[0][3]) { diag_set(arg1[0][2], &arg1[0][3]); } else if (arg1[1]) { diag_set(arg1[0][2], arg1[1]); ++arg1, --argc; } else { Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]); } break; case 's': /* stderr */ diag_set(arg1[0][2], NULL); break; case 'u': diag_set('u', NULL); break; case 'h': diag_set_int('h', true); break; default: Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]); break; } break; case 'v': xioparams->verbose = true; break; case 'x': xioparams->verbhex = true; break; case 'b': if (arg1[0][2]) { a = *arg1+2; } else { ++arg1, --argc; if ((a = *arg1) == NULL) { Error("option -b requires an argument; use option \"-h\" for help"); Exit(1); } } xioparams->bufsiz = strtoul(a, (char **)&a, 0); break; case 's': diag_set_int('e', E_FATAL); break; case 't': if (arg1[0][2]) { a = *arg1+2; } else { ++arg1, --argc; if ((a = *arg1) == NULL) { Error("option -t requires an argument; use option \"-h\" for help"); Exit(1); } } rto = strtod(a, (char **)&a); xioparams->closwait.tv_sec = rto; xioparams->closwait.tv_usec = (rto-xioparams->closwait.tv_sec) * 1000000; break; case 'T': if (arg1[0][2]) { a = *arg1+2; } else { ++arg1, --argc; if ((a = *arg1) == NULL) { Error("option -T requires an argument; use option \"-h\" for help"); Exit(1); } } rto = strtod(a, (char **)&a); xioparams->total_timeout.tv_sec = rto; xioparams->total_timeout.tv_usec = (rto-xioparams->total_timeout.tv_sec) * 1000000; break; case 'u': xioparams->lefttoright = true; break; case 'U': xioparams->righttoleft = true; break; case 'g': xioopts_ignoregroups = true; break; case 'L': if (socat_opts.lock.lockfile) Error("only one -L and -W option allowed"); if (arg1[0][2]) { socat_opts.lock.lockfile = *arg1+2; } else { ++arg1, --argc; if ((socat_opts.lock.lockfile = *arg1) == NULL) { Error("option -L requires an argument; use option \"-h\" for help"); Exit(1); } } break; case 'W': if (socat_opts.lock.lockfile) Error("only one -L and -W option allowed"); if (arg1[0][2]) { socat_opts.lock.lockfile = *arg1+2; } else { ++arg1, --argc; if ((socat_opts.lock.lockfile = *arg1) == NULL) { Error("option -W requires an argument; use option \"-h\" for help"); Exit(1); } } socat_opts.lock.waitlock = true; socat_opts.lock.intervall.tv_sec = 1; socat_opts.lock.intervall.tv_nsec = 0; break; #if WITH_IP4 || WITH_IP6 #if WITH_IP4 case '4': #endif #if WITH_IP6 case '6': #endif xioopts.default_ip = arg1[0][1]; xioopts.preferred_ip = arg1[0][1]; break; #endif /* WITH_IP4 || WITH_IP6 */ case 'c': switch (arg1[0][2]) { case 'S': xioparams->pipetype = XIOCOMM_SOCKETPAIRS; break; case 'P': case 'p': xioparams->pipetype = XIOCOMM_PIPES; break; case 's': xioparams->pipetype = XIOCOMM_SOCKETPAIR; break; case 'Y': xioparams->pipetype = XIOCOMM_PTYS; break; case 'y': xioparams->pipetype = XIOCOMM_PTY; break; case 't': xioparams->pipetype = XIOCOMM_TCP; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': xioparams->pipetype = atoi(&arg1[0][2]); break; default: Error1("bad chain communication type \"%s\"", &arg1[0][2]); } break; case '\0': case '-': /*! this is hardcoded "--" */ case ',': case ':': break; /* this "-" is a variation of STDIO or -- */ default: xioinqopt('p', buff, sizeof(buff)); if (arg1[0][1] == buff[0]) { break; } Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]); Exit(1); } /* the leading "-" might be a form of the first address */ xioinqopt('p', buff, sizeof(buff)); if (arg1[0][0] == '-' && (arg1[0][1] == '\0' || arg1[0][1] == ':' || arg1[0][1] == ',' || arg1[0][1] == '-'/*!*/ || arg1[0][1] == buff[0])) break; ++arg1; --argc; } #if 0 Info1("%d address arguments", argc); #else if (argc != 2) { Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc); Exit(1); } #endif if (xioparams->lefttoright && xioparams->righttoleft) { Error("-U and -u must not be combined"); } xioinitialize2(); Info(copyright_socat); #if WITH_OPENSSL Info(copyright_openssl); Info(copyright_ssleay); #endif Debug2("socat version %s on %s", socatversion, timestamp); xiosetenv("VERSION", socatversion, 1); /* SOCAT_VERSION */ uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */ Debug4("running on %s version %s, release %s, machine %s\n", ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine); #if WITH_MSGLEVEL <= E_DEBUG for (i = 0; i < argc0; ++i) { Debug2("argv[%d]: \"%s\"", i, argv[i]); } #endif /* WITH_MSGLEVEL <= E_DEBUG */ /* not sure what signal should print a message */ Signal(SIGHUP, socat_signal); Signal(SIGINT, socat_signal); Signal(SIGQUIT, socat_signal); Signal(SIGILL, socat_signal); /* SIGABRT for assert; catching caused endless recursion on assert in libc (tzfile.c:498: __tzfile_compute: Assertion 'num_types == 1' failed.) */ /*Signal(SIGABRT, socat_signal);*/ Signal(SIGBUS, socat_signal); Signal(SIGFPE, socat_signal); Signal(SIGSEGV, socat_signal); Signal(SIGTERM, socat_signal); #if HAVE_SIGACTION { struct sigaction act; memset(&act, 0, sizeof(struct sigaction)); act.sa_flags = SA_NOCLDSTOP|SA_RESTART|SA_SIGINFO #ifdef SA_NOMASK |SA_NOMASK #endif ; act.sa_sigaction = xiosigaction_subaddr_ok; if (Sigaction(SIGUSR1, &act, NULL) < 0) { /*! Linux man does not explicitely say that errno is defined */ Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno)); } } #else /* !HAVE_SIGACTION */ if (Signal(SIGUSR1, xiosigaction_subaddr_ok) == SIG_ERR) { Warn1("signal(SIGCHLD, xiosigaction_subaddr_ok): %s", strerror(errno)); } #endif /* !HAVE_SIGACTION */ /* set xio hooks */ xiohook_newchild = &socat_newchild; if (lockrc = socat_lock()) { /* =0: goon; >0: locked; <0: error, printed in sub */ if (lockrc > 0) Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile); Exit(1); } Atexit(socat_unlock); result = socat(argc, arg1[0], arg1[1]); Notice1("exiting with status %d", result); Exit(result); return 0; /* not reached, just for gcc -Wall */ }
static PT_THREAD(handle_bl(void)) { PT_BEGIN(&s.pt); s.retries = 3; do { flash_init(); tftpc_init(); tftpc_get(FIRMWARE_FILENAME); PT_WAIT_UNTIL(&s.pt, !tftpc_busy()); uint8_t rc = tftpc_result(); if(rc == TFTPC_FLASH_ERROR) { // any flash write errors, make sure the code doesn't run invalidate_code(); } // valid app code in place? if(!check_valid_code()) { // figure out what happened // and set indicator switch(rc) { case TFTPC_SUCCESS: diag_set(1); s.retries--; break; case TFTPC_SERVER_DOWN: diag_set(2); break; case TFTPC_FILE_NOT_FOUND: diag_set(3); break; case TFTPC_ERROR: diag_set(4); s.retries--; break; case TFTPC_FLASH_ERROR: diag_set(5); s.retries--; break; } } else { run_app(); } timer_set(&s.timer, RETRY_TIME); PT_WAIT_UNTIL(&s.pt, timer_expired(&s.timer)); } while (s.retries > 0); while(1) { PT_YIELD(&s.pt); } PT_END(&s.pt); }