The LuaSocket documentation says:
unconnected:sendto(datagram, ip, port)
If successful, the method returns 1. In case of error, the method
returns nil followed by an error message.
But I get a value of 4. What does return value of 4 means?
My code is here:
local socket = require("socket")
udp = socket.udp()
udp:setsockname("*", 8080)
local msg = "Test"
m=assert(udp:sendto( msg, "228.192.1.1", 8080))
print(m)
Looking closely at the source inside udp.c for sendo method
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;
}
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;
}
Basically, the documentation's "returns 1" statement is wrong. The return 1 statement in the code means that the actual function returns one value, which is actually pushed into the stack:
lua_pushnumber(L, (lua_Number) sent);
where the variable sent was calculated just a few statements above (check socket_sendto call.
So, the returned 4 is exactly what #moteus commented: The number of bytes sent.
sendto returns the number of bytes sent.
Related
I am trying to set up a UNIX domain socket in iOS. According to https://iphonedevwiki.net/index.php/Unix_sockets, this is the code that I used to set up the socket on the server side:
const char *socket_path = "/var/run/myserver.socket";
// setup socket
struct sockaddr_un local;
strcpy(local.sun_path, socket_path);
unlink(local.sun_path);
local.sun_family = AF_UNIX;
int listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
printf("listenfd: %d\n", listenfd);
// start the server
int r = -1;
while(r != 0) {
r = bind(listenfd, (struct sockaddr*)&local, sizeof(local));
printf("bind: %d\n", r);
usleep(200 * 1000);
}
int one = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
// start listening for new connections
r = -1;
while(r != 0) {
r = listen(listenfd, 20);
printf("listen: %d\n", r);
usleep(200 * 1000);
}
// wait for new connection, and then process it
int connfd = -1;
while(true) {
if(connfd == -1) {
// wait for new connection
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
printf("new connfd: %d\n", connfd);
}
// process incoming data
char buffer[4096];
int len = recv(connfd, buffer, sizeof(buffer), 0);
if(len == 0) {
printf("connfd %d disconnected!\n", connfd);
connfd = -1;
continue;
} else {
printf("connfd %d recieved data: %s", connfd, buffer);
// send some data back (optional)
const char *response = "got it!\n";
send(connfd, response, strlen(response) + 1, 0);
}
}
However, when I run this code on my iPhone, I got this in the console:
listenfd: 3
bind: -1
bind: -1
bind: -1
bind: -1
bind: -1
...
It looks like there is a problem when we do bind() as it returns -1, I want to know what I am doing wrong in the code?
The errno is 1, which is OPERATION_NOT_PERMITTED
You are not allowed to create objects in /var/run on iOS. You need to put the socket in a directory where you are allowed to create objects, like FileManager.shared.temporaryDirectory.
I am getting the following error when I try to compile with the code below it. I don't know how to fix it. I have googled. Also asked others, but nobody has been able to help me.
Compiling on mac through theos.
I would really appreciate it if someone can help me.
Error output
error: assigning to
'kern_return_t' (aka 'int') from incompatible type 'uint *'
(aka 'unsigned int *')
err = reinterpret_cast<uint *>(address* sizeof(data));
Code
bool writeData(vm_address_t address, string str) {
//declaring variables
kern_return_t err = 0;
mach_port_t port = mach_task_self();
size_t find = str.find("0x");
if (find != -1) {
str.replace(find, 2, "");
}
int len = str.size();
char data[len / 2];
int x = 0;
for(int i = 0; i < len; i += 2) {
string dat = str.substr(i, 2);
uint8_t tmp;
sscanf(dat.c_str(), "%hhx", &tmp);
data[x] = tmp;
x++;
}
//set memory protections to allow us writing code there
err = vm_protect(port, (vm_address_t)address, sizeof(data), NO, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
//check if the protection fails
if (err != KERN_SUCCESS)
return FALSE;
//write code to memory
err = reinterpret_cast<uint64_t *>(address* sizeof(data));
if (err != KERN_SUCCESS)
return FALSE;
//set the protections back to normal so the app can access this address as usual
err = vm_protect(port, (vm_address_t)address, sizeof(data), NO, VM_PROT_READ | VM_PROT_EXECUTE);
if (err != KERN_SUCCESS)
return FALSE;
return TRUE;
}
Hello fine community at stackoverflow! I've been lurking around using the site for about a year now, and just have come to the need to post a question.
I'm a bit of a klutz when it comes to coding, so go easy on me.
Here's the code (most of it is the sample winsock MSDN code :P):
Client:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
void clarify(char *recvdata);
char mdata[7];
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "10150"
int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("173.21.56.58", DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
// Send an initial buffer
char sendbuf[512];
std::cin.getline(sendbuf, 512);
iResult = send( ConnectSocket, sendbuf, 512, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
std::cout<<"sendbuf: "<<sendbuf<<"\n";
std::cout<<"strlen(sendbuf): "<<strlen(sendbuf)<<"\n";
printf("Bytes Sent: %ld\n", iResult);
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
std::cout<<"recvbuf: "<<recvbuf<<"\n";
std::cout<<"recvbuflen: "<<recvbuflen<<"\n";
std::cout<<"strlen(recvbuf): "<<strlen(recvbuf)<<"\n";
std::cout<<recvbuf[0]<<"\n";
std::cout<<recvbuf[1]<<"\n";
std::cout<<recvbuf[2]<<"\n";
std::cout<<recvbuf[3]<<"\n";
std::cout<<recvbuf[4]<<"\n";
std::cout<<recvbuf[5]<<"\n";
std::cout<<recvbuf[6]<<"\n";
std::cout<<recvbuf[7]<<"\n";
std::cout<<recvbuf[8]<<"\n";
std::cout<<recvbuf[9]<<"\n";
std::cout<<recvbuf[10]<<"\n";
std::cout<<recvbuf[11]<<"\n";
std::cout<<recvbuf[12]<<"\n";
clarify(recvbuf);
std::cout<<"mdata(main()): "<<mdata<<"\n";
if (mdata == "anarchy") {std::cout<<"This is Anarchy. :)";}
else {std::cout<<"Nope. :( ";}
} while( iResult > 0 );
std::cin.ignore();
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
void clarify(char *recvdata)
{
std::cout<<"recvdata: "<<recvdata<<"\n";
for (int i=0; i<(strlen(recvdata)); i++) {
mdata[i]=recvdata[i];
std::cout<<mdata[i]<<"\n";
}
std::cout<<"mdata(clarify()): "<<mdata<<"\n";
}
And the server code is the sample MSDN winsock code.
I realize the code has a bunch of sloppy extras added in, but rest assured, those are for my own thoughts and reminders. So, please don't bother telling me other places I could clean up. I'll take care of that when I get closer to finishing my project (a long way away :) ).
So, I'm having issues comparing the "mdata" variable with the characters "anarchy".
Even when I send "anarchy" through winsock, it comes back as "anarchy", and I run it through "clarify()" just for good measure, it still doesn't seem to equal "anarchy".
I'm sure it's a noob mistake I'm making here, so please go easy on me...
EDIT:
Here's the output after typing "anarchy" for the "sendbuf" input:
anarchy
sendbuf: anarchy
strlen(sendbuf): 7
bytes sent: 512
bytes recieved: 512
recvbuf: anarchy
recvbuflen: 512
strlen(recvbuf): 7
a
n
a
r
c
h
y
f
4
i
w
,
recvdata: anarchy
a
n
a
r
c
h
y
mdata(clarify()): anarchy
mdata(main()): anarchy
Nope :(
You're comparing the address of a c-string literal to the address stored in mdata.
if (mdata == "anarchy") {std::cout<<"This is Anarchy. :)";}
"anarchy" is a string literal, and has an address. You're comparing that arbitrary address with the address stored in the mdata variable. They're not the same addresses, so the equality check fails.
You don't mean to compare the addresses of where your two strings are stored, you mean to compare the characters stored at those strings.
strncmp is your friend here.
(iOS) I am trying to make SSL_connect with site https://login.11st.co.kr (I am using open ssl for extracting chains of PEM certificates) :
this is how I make Tcp connect
struct TcpConnectionInfo {
std::string ipAddress;
int socketId;
};
static TcpConnectionInfo TcpConnect(const char *host, int port) {
TcpConnectionInfo resultInfo;
resultInfo.socketId = kInvalidSocketId;
// TODO: gethostbyname is depricated, should replace with another
struct hostent *hp = gethostbyname(host);
if (hp == NULL) {
DLog(#"Couldn't resolve host");
return resultInfo;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_addr = *(struct in_addr*)hp->h_addr_list[0];
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
int socketId = (int)socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if (socketId < 0) {
DLog(#"Couldn't create socket");
return resultInfo;
}
int connectResult = connect(socketId, (struct sockaddr *)&addr, sizeof(addr));
if (connectResult < 0) {
DLog(#"Couldn't connect socket");
return resultInfo;
}
resultInfo.socketId = socketId;
resultInfo.ipAddress = inet_ntoa(addr.sin_addr);
return resultInfo;
}
that's how I am using it:
TcpConnectionInfo connectInfo = TcpConnect(url.c_str(), port);
SSL *ssl = SSL_new(ctx);
BIO *sbio = BIO_new_socket(connectInfo.socketId, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);
int sslConnectResult = SSL_connect(ssl);
i get error codes with code:
const int errorCode = SSL_get_error(ssl, sslConnectResult);
DLog(#"SSL Error Code: %d", errorCode);
DLog(#"errno: %d", errno);
and for site https://login.11st.co.kr it gives
SSL Error Code: 5 errno: 3
which corresponds to
SSL_ERROR_SYSCALL, ESRCH (No such process)
For other https sites all good.
What can it be? I cannot understand this error. How can I solve this? How it depends on processes?
It looks like the server is not responding from my location:
$ echo "GET / HTTP\1.0" | openssl s_client -showcerts -connect login.11st.co.kr:443
CONNECTED(00000003)
^C
SSL Error Code: 5 errno: 3
...
SSL_ERROR_SYSCALL, ESRCH (No such process)
This does not quite look right. When you get an error code from OpenSSL, you should be able to print it. The error code is usually a big hexadecimal number:
$ openssl errstr 5
error:00000005:lib(0):func(0):DH lib
Here's one that's more illustrative (i.e., what it usually looks like):
$ openssl errstr 0x2606c043
error:2606C043:engine routines:ENGINE_FREE_UTIL:passed a null parameter
BIO *sbio = BIO_new_socket(connectInfo.socketId, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);
int sslConnectResult = SSL_connect(ssl);
I usually just fetch the error code immediately after the operation. If the operation succeeds, I don't use the result because its not needed and undefined. If the operation fails, I can use the result because it is defined.
My BIO connect would look like:
unsigned long err;
int res;
...
BIO* web = BIO_new_ssl_connect(ctx);
err = ERR_get_error();
if(web == NULL)
{
const char* const str = ERR_reason_error_string(err);
fprintf(stderr, "%s\n", str);
exit (err);
}
res = BIO_set_conn_hostname(web, HOST_NAME ":" HOST_PORT);
err = ERR_get_error();
if(res != 1)
{
const char* const str = ERR_reason_error_string(err);
fprintf(stderr, "%s\n", str);
exit (err);
}
res = BIO_do_connect(web);
err = ERR_get_error();
if(res != 1)
{
const char* const str = ERR_reason_error_string(err);
fprintf(stderr, "%s\n", str);
exit (err);
}
...
ERR_reason_error_string is the C equivalent to the openssl errstr command.
You can see an example of a BIO-based client at SSL/TLS Client.
I have been having a lot of trouble finding a way to query the DNS to find the NAPTR in iOS. There seem to be many relatively simple ways to resolve to an IP, but I specifically need to find all NAPTR records in a DNS lookup. I'd prefer to do so without having to bring in any external libraries if at all possible. If anyone has been able to do this (or something similar that I can extrapolate from) I'd appreciate any pointers.
All code must function in iOS 5.0+
I ended up using DNSServiceQueryRecord.
DNSServiceRef sdRef;
DNSServiceQueryRecord(&sdRef, 0, 0,
"google.com",
kDNSServiceType_NAPTR,
kDNSServiceClass_IN,
callback,
NULL);
DNSServiceProcessResult(sdRef);
DNSServiceRefDeallocate(sdRef);
In actual use, I found that there was an issue where the app would hang indefinitely if there were no results, so I ended up having to adjust my code to add a timeout on the result.
/*
Attempt to fetch the NAPTR from the stored server address. Since iOS will continue waiting
until told directly to stop (even if there is no result) we must set our own timeout on the
request (set to 5 seconds).
On success, the callback function is called. On timeout, the kSRVLookupComplete notification
is sent.
*/
- (void)attemptNAPTRFetch {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DNSServiceRef sdRef;
DNSServiceErrorType err;
err = DNSServiceQueryRecord(&sdRef, 0, 0,
[server cStringUsingEncoding:[NSString defaultCStringEncoding]],
kDNSServiceType_NAPTR,
kDNSServiceClass_IN,
callback,
NULL);
// This stuff is necessary so we don't hang forever if there are no results
int dns_sd_fd = DNSServiceRefSockFD(sdRef);
int nfds = dns_sd_fd + 1;
fd_set readfds;
struct timeval tv;
int result;
int stopNow = 0;
int timeOut = 5; // Timeout in seconds
while (!stopNow) {
FD_ZERO(&readfds);
FD_SET(dns_sd_fd, &readfds);
tv.tv_sec = timeOut;
tv.tv_usec = 0;
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
if (result > 0) {
if(FD_ISSET(dns_sd_fd, &readfds)) {
err = DNSServiceProcessResult(sdRef);
if (err != kDNSServiceErr_NoError){
NSLog(#"There was an error");
}
stopNow = 1;
}
}
else {
printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
if (errno != EINTR) {
stopNow = 1;
postNotification(kSRVLookupComplete, nil);
}
}
}
DNSServiceRefDeallocate(sdRef);
});
}
Then, for the callback:
static void callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context)
{
uint16_t order, pref;
char flag;
NSMutableString *service = [[NSMutableString alloc] init];
NSMutableString *replacement = [[NSMutableString alloc] init];
const char *data = (const char*)rdata;
order = data[1];
pref = data[3];
flag = data[5];
int i = 7;
while (data[i] != 0){
[service appendString:[NSString stringWithFormat:#"%c", data[i]]];
i++;
}
i += 2;
while(data[i] != 0){
if(data[i] >= 32 && data[i] <= 127)
[replacement appendString:[NSString stringWithFormat:#"%c", data[i]]];
else
[replacement appendString:#"."];
i++;
}
NSLog(#"\nOrder: %i\nPreference: %i\nFlag: %c\nService: %#\nReplacement: %#\n", order, pref, flag, service, replacement);
}
This seems to do the trick for me. You would of course do any other necessary work using all the parsed data in the callback or store the data somewhere to be used later.