/*-------------------------------------------------------------------------*\ * Turns a master tcp object into a client object. \*-------------------------------------------------------------------------*/ static int meth_connect(lua_State *L) { const char *af_opts[] = {"AF_INET", "AF_INET6", "AF_UNSPEC"}; const char *def_af = "AF_UNSPEC"; p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); const char *address = luaL_checkstring(L, 2); unsigned short port = (unsigned short) luaL_checknumber(L, 3); short family; const char *err; p_timeout tm = timeout_markstart(&tcp->tm); switch(luaL_checkoption(L, 4, def_af, af_opts)) { case 0 : family = AF_INET ; break; case 1 : family = AF_INET6 ; break; case 2 : family = AF_UNSPEC ; break; default: family = AF_UNSPEC ; break; } err = inet_tryconnect(&tcp->sock, address, port, tm, family); /* have to set the class even if it failed due to non-blocking connects */ auxiliar_setclass(L, "tcp{client}", 1); if (err) { lua_pushnil(L); lua_pushstring(L, err); return 2; } /* turn master object into a client object */ lua_pushnumber(L, 1); return 1; }
/*-------------------------------------------------------------------------*\ * Waits for a set of sockets until a condition is met or timeout. \*-------------------------------------------------------------------------*/ static int global_select(lua_State *L) { int rtab, wtab, itab, ret, ndirty; t_socket max_fd; fd_set rset, wset; t_timeout tm; double t = luaL_optnumber(L, 3, -1); FD_ZERO(&rset); FD_ZERO(&wset); lua_settop(L, 3); lua_newtable(L); itab = lua_gettop(L); lua_newtable(L); rtab = lua_gettop(L); lua_newtable(L); wtab = lua_gettop(L); max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset); ndirty = check_dirty(L, 1, rtab, &rset); t = ndirty > 0? 0.0: t; timeout_init(&tm, t, -1); timeout_markstart(&tm); max_fd = collect_fd(L, 2, max_fd, itab, &wset); ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); if (ret > 0 || ndirty > 0) { return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); return_fd(L, &wset, max_fd+1, itab, wtab, 0); make_assoc(L, rtab); make_assoc(L, wtab); return 2; } else if (ret == 0) { lua_pushstring(L, "timeout"); return 3; } else { lua_pushstring(L, "error"); return 3; } }
/*-------------------------------------------------------------------------*\ * Send data through unconnected udp socket \*-------------------------------------------------------------------------*/ static int meth_sendto(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); size_t count, sent = 0; const char *data = luaL_checklstring(L, 2, &count); const char *ip = luaL_checkstring(L, 3); unsigned short port = (unsigned short) luaL_checknumber(L, 4); p_timeout tm = &udp->tm; struct sockaddr_in addr; int err; memset(&addr, 0, sizeof(addr)); if (!inet_aton(ip, &addr.sin_addr)) luaL_argerror(L, 3, "invalid ip address"); addr.sin_family = AF_INET; addr.sin_port = htons(port); timeout_markstart(tm); err = socket_sendto(&udp->sock, data, count, &sent, (SA *) &addr, sizeof(addr), tm); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); return 2; } lua_pushnumber(L, sent); return 1; }
/*-------------------------------------------------------------------------*\ * object:send() interface \*-------------------------------------------------------------------------*/ int buffer_meth_send(lua_State *L, p_buffer buf) { int top = lua_gettop(L); int err = IO_DONE; size_t size = 0, sent = 0; const char *data = luaL_checklstring(L, 2, &size); long start = (long) luaL_optnumber(L, 3, 1); long end = (long) luaL_optnumber(L, 4, -1); timeout_markstart(buf->tm); if (start < 0) start = (long) (size+start+1); if (end < 0) end = (long) (size+end+1); if (start < 1) start = (long) 1; if (end > (long) size) end = (long) size; if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); /* check if there was an error */ if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushnumber(L, (lua_Number) (sent+start-1)); } else { lua_pushnumber(L, (lua_Number) (sent+start-1)); lua_pushnil(L); lua_pushnil(L); } #ifdef LUASOCKET_DEBUG /* push time elapsed during operation as the last return value */ lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); #endif return lua_gettop(L) - top; }
/*-------------------------------------------------------------------------*\ * Receives data from a UDP socket \*-------------------------------------------------------------------------*/ static int meth_receive(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); char buf[UDP_DATAGRAMSIZE]; size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; int err; p_timeout tm = &udp->tm; timeout_markstart(tm); if (!dgram) { lua_pushnil(L); lua_pushliteral(L, "out of memory"); return 2; } err = socket_recv(&udp->sock, dgram, wanted, &got, tm); /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ if (err != IO_DONE && err != IO_CLOSED) { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); if (wanted > sizeof(buf)) free(dgram); return 2; } lua_pushlstring(L, dgram, got); if (wanted > sizeof(buf)) free(dgram); return 1; }
/*-------------------------------------------------------------------------*\ * Send data through unconnected udp socket \*-------------------------------------------------------------------------*/ static int meth_sendto(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); size_t count, sent = 0; const char *data = luaL_checklstring(L, 2, &count); const char *ip = luaL_checkstring(L, 3); const char *port = luaL_checkstring(L, 4); p_timeout tm = &udp->tm; int err; struct addrinfo aihint; struct addrinfo *ai; memset(&aihint, 0, sizeof(aihint)); aihint.ai_family = udp->family; aihint.ai_socktype = SOCK_DGRAM; aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; err = getaddrinfo(ip, port, &aihint, &ai); if (err) { lua_pushnil(L); lua_pushstring(L, gai_strerror(err)); return 2; } /* create socket if on first sendto if AF_UNSPEC was set */ if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) { struct addrinfo *ap; const char *errstr = NULL; for (ap = ai; ap != NULL; ap = ap->ai_next) { errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0); if (errstr == NULL) { socket_setnonblocking(&udp->sock); udp->family = ap->ai_family; break; } } if (errstr != NULL) { lua_pushnil(L); lua_pushstring(L, errstr); freeaddrinfo(ai); return 2; } } timeout_markstart(tm); err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, (socklen_t) ai->ai_addrlen, tm); freeaddrinfo(ai); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); return 2; } lua_pushnumber(L, (lua_Number) sent); return 1; }
/*-------------------------------------------------------------------------*\ * Send data through connected udp socket \*-------------------------------------------------------------------------*/ static int meth_send(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); p_timeout tm = &udp->tm; size_t count, sent = 0; int err; const char *data = luaL_checklstring(L, 2, &count); timeout_markstart(tm); err = socket_send(&udp->sock, data, count, &sent, tm); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); return 2; } lua_pushnumber(L, (lua_Number) sent); return 1; }
/*-------------------------------------------------------------------------*\ * Waits for and returns a client object attempting connection to the * server object \*-------------------------------------------------------------------------*/ static int meth_acceptfd(lua_State *L) { p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); p_timeout tm = timeout_markstart(&server->tm); t_socket sock; int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); /* if successful, push client socket */ if (err == IO_DONE) { lua_pushnumber(L, sock); return 1; } else { lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } }
/*-------------------------------------------------------------------------*\ * object:receive() interface \*-------------------------------------------------------------------------*/ int buffer_meth_receive(lua_State *L, p_buffer buf) { int err = IO_DONE, top = lua_gettop(L); luaL_Buffer b; size_t size; const char *part = luaL_optlstring(L, 3, "", &size); #ifdef LUASOCKET_DEBUG p_timeout tm = timeout_markstart(buf->tm); #endif /* initialize buffer with optional extra prefix * (useful for concatenating previous partial results) */ luaL_buffinit(L, &b); luaL_addlstring(&b, part, size); /* receive new patterns */ if (!lua_isnumber(L, 2)) { const char *p= luaL_optstring(L, 2, "*l"); if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); else luaL_argcheck(L, 0, 2, "invalid receive pattern"); /* get a fixed number of bytes (minus what was already partially * received) */ } else { double n = lua_tonumber(L, 2); size_t wanted = (size_t) n; luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); if (size == 0 || wanted > size) err = recvraw(buf, wanted-size, &b); } /* check if there was an error */ if (err != IO_DONE) { /* we can't push anyting in the stack before pushing the * contents of the buffer. this is the reason for the complication */ luaL_pushresult(&b); lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushvalue(L, -2); lua_pushnil(L); lua_replace(L, -4); } else { luaL_pushresult(&b); lua_pushnil(L); lua_pushnil(L); } #ifdef LUASOCKET_DEBUG /* push time elapsed during operation as the last return value */ lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); #endif return lua_gettop(L) - top; }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { #ifdef LUASOCKET_SECURITY_SANDBOX if (luasocket_ip_allowed(address)) return "connect restricted"; #endif // LUASOCKET_SECURITY_SANDBOX struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* create new socket if necessary. if there was no * bind, we need to create one for every new family * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; /* set non-blocking before connect */ socket_setnonblocking(ps); } /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success or timeout is zero, break out of loop */ if (err == NULL || timeout_iszero(tm)) { *family = current_family; break; } } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/*-------------------------------------------------------------------------*\ * Receives data from a UDP socket \*-------------------------------------------------------------------------*/ static int meth_receive(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); char buffer[UDP_DATAGRAMSIZE]; size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); int err; p_timeout tm = &udp->tm; count = MIN(count, sizeof(buffer)); timeout_markstart(tm); err = socket_recv(&udp->sock, buffer, count, &got, tm); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); return 2; } lua_pushlstring(L, buffer, got); return 1; }
/*-------------------------------------------------------------------------*\ * Turns a master tcp object into a client object. \*-------------------------------------------------------------------------*/ static int meth_connect(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); const char *address = luaL_checkstring(L, 2); unsigned short port = (unsigned short) luaL_checknumber(L, 3); p_timeout tm = timeout_markstart(&tcp->tm); const char *err = inet_tryconnect(&tcp->sock, address, port, tm); /* have to set the class even if it failed due to non-blocking connects */ auxiliar_setclass(L, "tcp{client}", 1); if (err) { lua_pushnil(L); lua_pushstring(L, err); return 2; } /* turn master object into a client object */ lua_pushnumber(L, 1); return 1; }
static int global_select(lua_State *L, const sigset_t* mask, int sigreceived) { int rtab, wtab, etab, itab, ret, ndirty; t_socket max_fd; fd_set rset, wset, eset; t_timeout tm; double t = luaL_optnumber(L, 4, -1); FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); lua_settop(L, 4); lua_newtable(L); itab = lua_gettop(L); lua_newtable(L); rtab = lua_gettop(L); lua_newtable(L); wtab = lua_gettop(L); lua_newtable(L); etab = lua_gettop(L); max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset); ndirty = check_dirty(L, 1, rtab, &rset); t = ndirty > 0? 0.0: t; timeout_init(&tm, t, -1); timeout_markstart(&tm); max_fd = collect_fd(L, 2, max_fd, itab, &wset); max_fd = collect_fd(L, 3, max_fd, itab, &eset); //printf("+enter select\n"); if (sigreceived) { ret = -1; } else { ret = socket_select(max_fd+1, &rset, &wset, &eset, &tm, mask); } //printf("+exit select\n"); if (ret > 0 || ndirty > 0) { return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); return_fd(L, &wset, max_fd+1, itab, wtab, 0); return_fd(L, &eset, max_fd+1, itab, etab, 0); make_assoc(L, rtab); make_assoc(L, wtab); make_assoc(L, etab); return 3; //3 values pushed: 3 result tables } else if (ret == 0) { lua_pushstring(L, "timeout"); return 4; //4 values pushed: 3 result tables + timeout msg } else { lua_pushstring(L, strerror(errno)); return 4; //4 values pushed: 3 result tables + errno msg } }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* create new socket if necessary. if there was no * bind, we need to create one for every new family * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ if (*family != iterator->ai_family) { socket_destroy(ps); err = socket_strerror(socket_create(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); if (err != NULL) { freeaddrinfo(resolved); return err; } *family = iterator->ai_family; /* all sockets initially non-blocking */ socket_setnonblocking(ps); } /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/*-------------------------------------------------------------------------*\ * Turns a master unix object into a client object. \*-------------------------------------------------------------------------*/ static const char *unix_tryconnect(p_unix un, const char *path) { struct sockaddr_un remote; int err; size_t len = strlen(path); if (len >= sizeof(remote.sun_path)) return "path too long"; memset(&remote, 0, sizeof(remote)); strcpy(remote.sun_path, path); remote.sun_family = AF_UNIX; timeout_markstart(&un->tm); #ifdef UNIX_HAS_SUN_LEN remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) + len + 1; err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm); #else err = socket_connect(&un->sock, (SA *) &remote, sizeof(remote.sun_family) + len, &un->tm); #endif if (err != IO_DONE) socket_destroy(&un->sock); return socket_strerror(err); }
/*-------------------------------------------------------------------------*\ * Receives data and sender from a UDP socket \*-------------------------------------------------------------------------*/ static int meth_receivefrom(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); char buf[UDP_DATAGRAMSIZE]; size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); char addrstr[INET6_ADDRSTRLEN]; char portstr[6]; int err; p_timeout tm = &udp->tm; timeout_markstart(tm); if (!dgram) { lua_pushnil(L); lua_pushliteral(L, "out of memory"); return 2; } err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, &addr_len, tm); /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ if (err != IO_DONE && err != IO_CLOSED) { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); if (wanted > sizeof(buf)) free(dgram); return 2; } err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); if (err) { lua_pushnil(L); lua_pushstring(L, gai_strerror(err)); if (wanted > sizeof(buf)) free(dgram); return 2; } lua_pushlstring(L, dgram, got); lua_pushstring(L, addrstr); lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); if (wanted > sizeof(buf)) free(dgram); return 3; }
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, struct addrinfo *connecthints, p_tcp tcp) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } /* iterate over all returned addresses trying to connect */ for (iterator = resolved; iterator; iterator = iterator->ai_next) { p_timeout tm = timeout_markstart(&tcp->tm); /* create new socket if one wasn't created by the bind stage */ if (tcp->sock == SOCKET_INVALID) { err = socket_strerror(socket_create(&tcp->sock, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); if (err != NULL) { freeaddrinfo(resolved); return err; } tcp->family = iterator->ai_family; /* all sockets initially non-blocking */ socket_setnonblocking(&tcp->sock); } /* finally try connecting to remote address */ err = socket_strerror(socket_connect(&tcp->sock, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/** * Perform the TLS/SSL handshake */ static int handshake(p_ssl ssl) { int err; p_timeout tm = timeout_markstart(&ssl->tm); if (ssl->state == ST_SSL_CLOSED) return IO_CLOSED; for ( ; ; ) { ERR_clear_error(); err = SSL_do_handshake(ssl->ssl); ssl->error = SSL_get_error(ssl->ssl, err); switch(ssl->error) { case SSL_ERROR_NONE: ssl->state = ST_SSL_CONNECTED; return IO_DONE; case SSL_ERROR_WANT_READ: err = socket_waitfd(&ssl->sock, WAITFD_R, tm); if (err == IO_TIMEOUT) return IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_WANT_WRITE: err = socket_waitfd(&ssl->sock, WAITFD_W, tm); if (err == IO_TIMEOUT) return IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_SYSCALL: if (ERR_peek_error()) { ssl->error = SSL_ERROR_SSL; return IO_SSL; } if (err == 0) return IO_CLOSED; return socket_error(); default: return IO_SSL; } } return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Turns a master tcp object into a client object. \*-------------------------------------------------------------------------*/ static int meth_connect(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); const char *address = luaL_checkstring(L, 2); const char *port = luaL_checkstring(L, 3); struct addrinfo connecthints; const char *err; memset(&connecthints, 0, sizeof(connecthints)); connecthints.ai_socktype = SOCK_STREAM; /* make sure we try to connect only to the same family */ connecthints.ai_family = tcp->family; timeout_markstart(&tcp->tm); err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints); /* have to set the class even if it failed due to non-blocking connects */ auxiliar_setclass(L, "tcp{client}", 1); if (err) { lua_pushnil(L); lua_pushstring(L, err); return 2; } lua_pushnumber(L, 1); return 1; }
/*-------------------------------------------------------------------------*\ * Waits for and returns a client object attempting connection to the * server object \*-------------------------------------------------------------------------*/ static int meth_accept(lua_State *L) { p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1); p_timeout tm = timeout_markstart(&server->tm); t_socket sock; int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); /* if successful, push client socket */ if (err == IO_DONE) { p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix)); auxiliar_setclass(L, "unix{client}", -1); /* initialize structure fields */ socket_setnonblocking(&sock); clnt->sock = sock; io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, (p_error) socket_ioerror, &clnt->sock); timeout_init(&clnt->tm, -1, -1); buffer_init(&clnt->buf, &clnt->io, &clnt->tm); return 1; } else { lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } }
/*-------------------------------------------------------------------------*\ * Receives data and sender from a UDP socket \*-------------------------------------------------------------------------*/ static int meth_receivefrom(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); char buffer[UDP_DATAGRAMSIZE]; size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); int err; p_timeout tm = &udp->tm; timeout_markstart(tm); count = MIN(count, sizeof(buffer)); err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, &addr_len, tm); if (err == IO_DONE) { lua_pushlstring(L, buffer, got); lua_pushstring(L, inet_ntoa(addr.sin_addr)); lua_pushnumber(L, ntohs(addr.sin_port)); return 3; } else { lua_pushnil(L); lua_pushstring(L, udp_strerror(err)); return 2; } }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/** * initialize and open a SACD device or file. */ static sacd_input_t sacd_net_input_open(const char *target) { ServerRequest request; ServerResponse response; sacd_input_t dev = 0; const char *err = 0; t_timeout tm; pb_istream_t input; pb_ostream_t output; uint8_t zero = 0; /* Allocate the library structure */ dev = (sacd_input_t) calloc(sizeof(*dev), 1); if (dev == NULL) { fprintf(stderr, "libsacdread: Could not allocate memory.\n"); return NULL; } dev->input_buffer = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); if (dev->input_buffer == NULL) { fprintf(stderr, "libsacdread: Could not allocate memory.\n"); goto error; } socket_open(); socket_create(&dev->fd, AF_INET, SOCK_STREAM, 0); socket_setblocking(&dev->fd); timeout_markstart(&tm); err = inet_tryconnect(&dev->fd, substr(target, 0, strchr(target, ':') - target), atoi(strchr(target, ':') + 1), &tm); if (err) { fprintf(stderr, "Failed to connect\n"); goto error; } socket_setblocking(&dev->fd); input = pb_istream_from_socket(&dev->fd); output = pb_ostream_from_socket(&dev->fd); request.type = ServerRequest_Type_DISC_OPEN; if (!pb_encode(&output, ServerRequest_fields, &request)) { fprintf(stderr, "Failed to encode request\n"); goto error; } /* We signal the end of request with a 0 tag. */ pb_write(&output, &zero, 1); if (!pb_decode(&input, ServerResponse_fields, &response)) { fprintf(stderr, "Failed to decode response\n"); goto error; } if (response.result != 0 || response.type != ServerResponse_Type_DISC_OPENED) { fprintf(stderr, "Response result non-zero or disc opened\n"); goto error; } return dev; error: sacd_input_close(dev); return 0; }