below is the lua table i need to read from C:
listen = {
{ port = 1234, address = "192.168.1.1", userdata = "liunx" },
{ port = 1235, address = "192.168.1.2", userdata = "liunx1" },
{ port = 1236, address = "192.168.1.3", userdata = "liunx2" }
}
below is the c code:
#include <lua.h> /* Always include this when calling Lua */
#include <lauxlib.h> /* Always include this when calling Lua */
#include <lualib.h> /* Prototype for luaL_openlibs(), */
/* always include this when calling Lua */
#include <stdlib.h> /* For function exit() */
#include <stdio.h> /* For input/output */
void bail(lua_State *L, char *msg){
fprintf(stderr, "\nFATAL ERROR:\n %s: %s\n\n",
msg, lua_tostring(L, -1));
exit(1);
}
int main(void)
{
lua_State *L;
L = luaL_newstate(); /* Create Lua state variable */
luaL_openlibs(L); /* Load Lua libraries */
if (luaL_loadfile(L, "cfg.lua"))
bail(L, "luaL_loadfile() failed");
if (lua_pcall(L, 0, 0, 0))
bail(L, "lua_pcall() failed");
// how to read???
lua_getglobal(L, "listen");
lua_close(L);
return 0;
}
I want to travel this table which may contain a few number of data in while loop, but really do not know how to do it, so any tips?
Thanks very much for your tips!Below are the worked code:
#include <lua.h> /* Always include this when calling Lua */
#include <lauxlib.h> /* Always include this when calling Lua */
#include <lualib.h> /* Prototype for luaL_openlibs(), */
/* always include this when calling Lua */
#include <stdlib.h> /* For function exit() */
#include <stdio.h> /* For input/output */
void bail(lua_State *L, char *msg)
{
fprintf(stderr, "\nFATAL ERROR:\n %s: %s\n\n",
msg, lua_tostring(L, -1));
exit(1);
}
int main(void)
{
lua_State *L;
static struct {
const char * name;
int type;
} fields[] = {
{"port", LUA_TNUMBER},
{"address", LUA_TSTRING},
{"userdata", LUA_TSTRING},
{NULL, 0}
};
L = luaL_newstate(); /* Create Lua state variable */
luaL_openlibs(L); /* Load Lua libraries */
if (luaL_loadfile(L, "cfg.lua"))
bail(L, "luaL_loadfile() failed");
if (lua_pcall(L, 0, 0, 0))
bail(L, "lua_pcall() failed");
lua_getglobal(L, "listen");
luaL_checktype(L, -1, LUA_TTABLE);
int i;
for (i = 1; ; i++) {
lua_rawgeti(L, -1, i);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
// an element of the 'listen' table should now be at the top of the stack
luaL_checktype(L, -1, LUA_TTABLE);
// read the content of that element
int field_index;
for (field_index = 0; (fields[field_index].name != NULL
&& fields[field_index].name != NULL); field_index++) {
lua_getfield(L, -1, fields[field_index].name);
luaL_checktype(L, -1, fields[field_index].type);
// you should probably use a function pointer in the fields table.
// I am using a simple switch/case here
switch(field_index) {
case 0:
printf("port: %d\n", (int)lua_tonumber(L, -1));
// do what you want with port
break;
case 1:
printf("address: %s\n", lua_tostring(L, -1));
break;
case 2:
// handle userdata
printf("userdata: %s\n", lua_tostring(L, -1));
break;
}
// remove the field value from the top of the stack
lua_pop(L, 1);
}
// remove the element of the 'listen' table from the top of the stack.
lua_pop(L, 1);
}
lua_close(L);
return 0;
}
You are not too far. The key here is to understand how the Lua API use the stack for everything.
Here is an untested code sample which should get you going:
// this will be used to validate our table
static struct {
const char * name;
int type;
} fields[] = {
{"port", LUA_TNUMBER},
{"address", LUA_TSTRING},
{"userdata", LUA_TSTRING},
NULL
};
lua_getglobal(L, "listen");
// the 'listen' table should be at the top of the stack
luaL_checktype(L, -1, LUA_TTABLE);
// iterate the listen table
int i;
for (i = 1; ; i++) {
lua_rawgeti(L, -1, i);
// when you get nil, you're done
if (lua_isnil(L, -1)) {
lua_pop(L,1);
break;
}
// an element of the 'listen' table should now be at the top of the stack
luaL_checktype(L, -1, LUA_TTABLE);
// read the content of that element
int field_index;
for (field_index = 0; fields[field_index] != NULL; field_index++) {
lua_getfield(L, -1, fields[field_index].name);
luaL_checktype(L, -1, fields[field_index].type);
// you should probably use a function pointer in the fields table.
// I am using a simple switch/case here
switch(field_index) {
case 0:
port = lua_tonumber(L, -1);
// do what you want with port
break;
case 1:
address = lua_tostring(L, -1);
break;
case 2:
// handle userdata
break;
}
// remove the field value from the top of the stack
lua_pop(L, 1);
}
// remove the element of the 'listen' table from the top of the stack.
lua_pop(L, 1);
}
I suggest you use those documentations: Lua API table Lua API ref
Related
I am currently developing an application for my ESP32 for which I need to use the Lua-C-API.
My goal would be to call a Lua function named "add" from C and flash the program on the ESP32.
So, in the Lua code ("add.lua") I define function "add":
-- add two numbers
function add ( x, y )
return x + y
end
My C code for calling the interface is the following:
/* Function luaadd */
int luaadd (lua_State* L, int x, int y ) {
int sum;
/* the function name */
lua_getglobal(L, "add");
/* the first argument */
lua_pushnumber(L, x);
/* the second argument */
lua_pushnumber(L, y);
/* call the function with 2 arguments, return 1 result */
lua_call(L, 2, 1);
/* get the result */
sum = (int)lua_tointeger(L, -1);
lua_pop(L, 1);
return sum;
}
/* Main function */
void app_main()
{
initialize_nvs();
#if CONFIG_STORE_HISTORY
initialize_filesystem();
#endif
initialize_console();
/* initialize Lua */
lua_State* L = luaL_newstate();
luaL_openlibs(L);
openlibs(L);
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_io(L); /* opens the I/O library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */
/* load Lua file */
if (luaL_loadfile(L, "add.lua")){
printf("Error loading file: %s", lua_tostring(L, -1));
}
/* call the add function */
int sum;
sum = luaadd(L, 10, 15 );
/* print the result */
printf( "The sum is %d\n", sum );
/* cleanup Lua */
lua_close(L);
/* print 'Finished' to console */
printf("Finished");
}
And this is the entire C file:
#include <modules.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "esp_vfs_fat.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "sb.h"
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
static const char* TAG = "Console";
/* Console command history can be stored to and loaded from a file.
* The easiest way to do this is to use FATFS filesystem on top of
* wear_levelling library.
*/
#if CONFIG_STORE_HISTORY
#define MOUNT_PATH "/data"
#define HISTORY_PATH MOUNT_PATH "/history.txt"
static void initialize_filesystem()
{
static wl_handle_t wl_handle;
const esp_vfs_fat_mount_config_t mount_config = {
.max_files = 4,
.format_if_mount_failed = true
};
esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount FATFS (0x%x)", err);
return;
}
}
#endif // CONFIG_STORE_HISTORY
static void initialize_nvs()
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK( nvs_flash_erase() );
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
}
static void initialize_console()
{
/* Disable buffering on stdin and stdout */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 8,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK( esp_console_init(&console_config) );
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
#endif
}
int luaadd (lua_State* L, int x, int y )
{
int sum;
/* the function name */
lua_getglobal(L, "add");
/* the first argument */
lua_pushnumber(L, x);
/* the second argument */
lua_pushnumber(L, y);
/* call the function with 2 arguments, return 1 result */
lua_call(L, 2, 1);
/* get the result */
sum = (int)lua_tointeger(L, -1);
lua_pop(L, 1);
return sum;
}
void app_main()
{
initialize_nvs();
#if CONFIG_STORE_HISTORY
initialize_filesystem();
#endif
initialize_console();
/* initialize Lua */
lua_State* L = luaL_newstate();
luaL_openlibs(L);
openlibs(L);
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_io(L); /* opens the I/O library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */
/* load Lua file */
if (luaL_loadfile(L, "add.lua")){
printf("Error loading file: %s", lua_tostring(L, -1));
}
/* call the add function */
int sum;
sum = luaadd(L, 10, 15 );
/* print the result */
printf( "The sum is %d\n", sum );
/* cleanup Lua */
lua_close(L);
/* print 'Finished' to console */
printf("Finished");
}
When I now flash this onto my ESP32 I get the following message:
Error loading file: cannot open add.lua: No such file or
directoryPANIC: unprotected error in call to Lua API (attempt to call
a nil value) abort() was called at PC 0x4016b808 on core 0
Do you know how to solve the problem? My "add.lua" file is in the same directory as the C file.
As stated in this post, you need ./add.lua to load your file from the current directory. You can also try with an absolute path.
luaL_loadfile only loads the file but does not execute its contents. The function add is only defined when the file is executed. Use luaL_dofile to load and execute a file.
I would like to wrap the C timer (not alarm) and use it within lua, in a way that I
could specify a callback function to be triggered after one second have passed.
In order to use multiple timer, a timer ID and callback will be stored to a table,
but a Segmentation fault occured when 'lua_rawset' was called, so I use stack_dump
check the lua stack, a nil was returned by 'lua_rawget' on line 66(lr_register_timer,
marked by FIXME), what is wrong here? Sorry, my English is poor.
Cheers.
lua code:
local lt = luatimer
lt.register_timer(1, function(id)
io.stdout:write("id" .. id .. "timeout\n");
end)
C code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "timer.h"
static lua_State *L;
static void stack_dump(lua_State *L, FILE *fp)
{
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++) {
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: fprintf(fp, "'%s'", lua_tostring(L, i)); break;
case LUA_TBOOLEAN: fprintf(fp, lua_toboolean(L, i) ? "true" : "false"); break;
case LUA_TNUMBER: fprintf(fp, "%g", lua_tonumber(L, i)); break;
default: fprintf(fp, "%s", lua_typename(L, t)); break;
}
fprintf(fp, " ");
}
fprintf(fp, "\n");
}
struct timer_env {
int id;
struct event *ev;
};
static void callback_timer_wrap(int id, void *arg)
{
struct timer_env *env = arg;
/* get timer id table */
lua_pushlightuserdata(L, &L);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushinteger(L, env->id);
lua_gettable(L, -2);
/* call lua handler with one result */
lua_pushinteger(L, env->id);
if (lua_pcall(L, 1, 1, 0) == 0) {
lua_pop(L, 1); /* pop result */
}
}
/* id, callback */
static int lr_register_timer(lua_State *L)
{
struct timer_env *env;
int id;
int err;
id = (int)luaL_checkinteger(L, 1);
if (!lua_isfunction(L, 2) || lua_iscfunction(L, 2))
return 0;
/* set lua handler */
lua_pushlightuserdata(L, &L);
lua_rawget(L, LUA_REGISTRYINDEX); /* FIXME */
lua_pushvalue(L, 1); /* key: id */
lua_pushvalue(L, 2); /* value: callback */
stack_dump(L, stderr);
/* FIXME crashed */
lua_rawset(L, -3);
lua_pop(L, 1);
env = malloc(sizeof(*env));
memset(env, 0, sizeof(*env));
env->id = id;
if ((err = register_timer(id, callback_timer_wrap, env)) < 0)
free(env);
lua_pushinteger(L, err);
return 1;
}
static const luaL_Reg luatimer_lib[] = {
{ "register_timer", lr_register_timer },
{ NULL, NULL }
};
static int luaopen_luatimer(lua_State *L)
{
luaL_register(L, "luatimer", luatimer_lib);
/* timer id table */
lua_pushlightuserdata(L, &L); /* key */
lua_newtable(L); /* value */
lua_rawset(L, LUA_REGISTRYINDEX);
return 1;
}
int luaenv_init(void)
{
L = luaL_newstate();
luaL_openlibs(L);
lua_pushcfunction(L, luaopen_luatimer);
lua_pushstring(L, "luatimer");
lua_call(L, 1, 0);
return 0;
}
void luaenv_exit(void)
{
if (L)
lua_close(L);
}
Thank you very much, I make a stupid mistake that I use the same name L in local vars and global vars. I'm Sorry
Thanks greatwold and immibis
I can't figure out why this is happening, but it is, and it's weird. I'm brewing up a server to learn more about socket programming and the C-Lua API as well, and it works perfectly fine except for one (not-so-minor) hiccup.
So far, all it does is accept connections, and check for readable connections, then reads from them. It passes what it read to a Lua function in a Lua state specific to that connection, which then echoes it back to the client (as well as printing it out for the server).
For some reason, string concatenation is behaving really strangely. I can't reproduce it in a simple test program, so I don't know what's causing it. Basically, here's my lua/state.lua file:
function OnRead(...)
local s = table.concat({...})
print(s)
s = 'You sent the string: "' .. s .. '" and then some stuff at the end.'
print(s)
send(s)
end
So, as you can see, pretty simple. The first print(s) will work fine. However, once I concatenate, the stuff at the end (i.e, the " and then some stuff at the end.) will get written over the start of the string! So if the input is the string "Hello World." then s won't become:
You sent the string: "Hello World." and then some stuff at the end.
but rather:
"and then some stuff at the end.d.
And I can't for the life of my figure out why it's doing this! It's a problem specific to the following code, as I can't reproduce it in a small simple program, but I don't know what could cause the Lua script to so strangely misbehave.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define SERVER_PORT 5000
#define READ_OVERFLOW_SIZE_LIMIT 4098 /* maximum socket line length */
#define READ_BUFFER_SIZE 4098
#define BUFFER_SIZE 1024
#define SHORT_BUFFER_SIZE 64
#define STATE_LUA_FILE "lua/state.lua"
/* L_ prefix for Lua registry table keys */
#define L_CONNFD "server_connfd"
/* G_ prefix for Lua global table keys */
#define G_ONREAD_HANDLER "OnRead"
typedef struct node_t {
struct node_t *next;
struct node_t *prev;
int value;
lua_State *state;
} ll_conn_t;
/*-----------------------------------------------------------------------------
* Appends a connection tuple to a linked list. Returns 0 on success, or a -1
* on error.
* If the connfd value is already present in the linked list, it will error.
*---------------------------------------------------------------------------*/
int ll_conn_append(ll_conn_t *list, int value, lua_State *state)
{
ll_conn_t *temp;
for (temp = list; temp->next != NULL; temp = temp->next)
{
if (temp->next->value == value)
return -1;
}
temp->next = (ll_conn_t *)malloc(sizeof(ll_conn_t));
temp->next->prev = temp;
temp->next->next = NULL;
temp->next->value = value;
temp->next->state = state;
list->value++;
return 0;
} /*----- end of function ll_conn_append -----*/
/*-----------------------------------------------------------------------------
* Creates a new linked list and returns a pointer to the new linked list.
*---------------------------------------------------------------------------*/
ll_conn_t *ll_conn_create()
{
ll_conn_t *list = (ll_conn_t *)malloc(sizeof(ll_conn_t));
list->next = NULL;
list->prev = NULL;
list->value = 0;
list->state = NULL;
return list;
} /*----- end of function ll_conn_create -----*/
/*-----------------------------------------------------------------------------
* Iterates over a linked list and completely frees up its memory.
*---------------------------------------------------------------------------*/
void ll_conn_delete(ll_conn_t *list)
{
ll_conn_t *temp;
for (temp = list->next; temp != NULL; list = temp, temp = temp->next)
{
lua_close(list->state);
free(list);
}
} /*----- end of function ll_conn_delete -----*/
/*-----------------------------------------------------------------------------
* Searches for and removes the first occurrence of a specific connfd from a
* linked list. Returns a boolean which indicates whether the value was found.
*---------------------------------------------------------------------------*/
int ll_conn_remove(ll_conn_t *list, int value)
{
ll_conn_t *iter, *temp;
for (iter = list; iter->next != NULL; iter = iter->next)
{
temp = iter->next;
if (temp->value == value)
{
iter->next = temp->next;
if (temp->next != NULL)
temp->next->prev = iter;
lua_close(temp->state);
free(temp);
list->value--;
return 1;
}
}
return 0;
} /*----- end of function ll_conn_remove -----*/
/*-----------------------------------------------------------------------------
* lua_CFunction
* Takes a string argument, and writes that string to this Lua state's socket
* connection.
*---------------------------------------------------------------------------*/
int luasend(lua_State *L)
{
int connfd, success, length;
lua_pushstring(L, L_CONNFD);
lua_rawget(L, LUA_REGISTRYINDEX);
connfd = (int)lua_tointegerx(L, -1, &success);
lua_pop(L, 1);
if (!success)
{
/* error! */
lua_pushstring(L, "Socket connfd could not be converted to integer!");
lua_error(L);
}
length = luaL_len(L, -1);
write(connfd, lua_tostring(L, -1), length);
lua_pop(L, 1);
return 0;
} /*----- end of function luasend -----*/
/*-----------------------------------------------------------------------------
* Takes as input a connected socket file descriptor and builds a new Lua
* state for that socket.
*---------------------------------------------------------------------------*/
lua_State *l_create_state(int connfd)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushstring(L, L_CONNFD);
lua_pushinteger(L, connfd);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_register(L, "send", *luasend);
luaL_dofile(L, STATE_LUA_FILE);
return L;
} /*----- end of function l_create_state -----*/
/*-----------------------------------------------------------------------------
* Reads from the Lua state's connection, and calls the Lua handler for each
* line it encounters in the read buffer.
*---------------------------------------------------------------------------*/
void l_read_conn(lua_State *L, int connfd)
{
static char buffer[READ_BUFFER_SIZE];
int count = 1, i, start, overflow_count = 0, overflow_size = 0, len;
while (1)
{
ioctl(connfd, FIONREAD, &len);
if (len == 0)
break;
count = read(connfd, buffer, READ_BUFFER_SIZE);
if (count == -1)
{
/* TODO error handling */
break;
}
if (count == 0)
{
/* EOF */
break;
}
start = 0;
for (i = 0; i < count; i++)
{
if (buffer[i] != '\n')
continue;
if (!overflow_count)
lua_getglobal(L, G_ONREAD_HANDLER);
/* We won't be passing newlines to the handler. Otherwise, it would
* be 1 + i - start. */
lua_pushlstring(L, buffer + start, i - start);
lua_call(L, 1, 0);
overflow_count = overflow_size = 0;
start = i + 1;
}
/* If there's bits in the buffer that aren't terminated with a newline,
* add it as overflow to the stack.
* NOTE: THIS IS A REALLY BAD IDEA !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
if (start < count)
{
if (!overflow_count)
lua_getglobal(L, G_ONREAD_HANDLER);
lua_pushlstring(L, buffer + start, count - start);
overflow_size += count - start;
overflow_count++;
/* let's include this check to make this a marginally less bad idea
* in order to soothe my OCD worries */
if (overflow_size >= READ_OVERFLOW_SIZE_LIMIT)
break;
}
}
if (overflow_count)
lua_call(L, overflow_count, 0);
} /*----- end of function l_read_conn -----*/
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0, maxfd = 0;
struct sockaddr_in serv_addr, conn_addr;
char sendBuff[BUFFER_SIZE];
lua_State *L;
fd_set fds;
ll_conn_t *connections = ll_conn_create();
/* iterators */
ll_conn_t *temp;
int n;
unsigned int i, j;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
/* TODO error handling */
}
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', BUFFER_SIZE);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERVER_PORT);
if (bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0)
{
/* TODO error handling */
}
if (listen(listenfd, 10) == -1)
{
/* TODO error handling */
}
while (1)
{
FD_ZERO(&fds);
FD_SET(listenfd, &fds);
if (listenfd >= maxfd)
maxfd = listenfd + 1;
for (temp = connections->next; temp != NULL; temp = temp->next)
FD_SET(temp->value, &fds);
if ((n = select(maxfd, &fds, NULL, NULL, NULL)) > 0)
{
if (FD_ISSET(listenfd, &fds))
{
i = sizeof(conn_addr);
connfd = accept(listenfd, (struct sockaddr *)&conn_addr, &i);
if (connfd < 0)
{
/* TODO error handling */
}
L = l_create_state(connfd); /* create new state */
if (ll_conn_append(connections, connfd, L) < 0)
{
/* TODO error handling */
}
if (connfd >= maxfd)
maxfd = connfd + 1;
printf("New connection from %s.\n",
inet_ntoa(conn_addr.sin_addr));
}
/* we do iteration this way so that we don't segfault!!! */
for (temp = connections->next; temp != NULL;)
{
connfd = temp->value;
L = temp->state;
temp = temp->next;
if (FD_ISSET(connfd, &fds))
{
/* check connection status */
ioctl(connfd, FIONREAD, &j);
if (j == 0)
{
/* the socket should now be removed! */
ll_conn_remove(connections, connfd);
}
else
{
/* read from connection */
l_read_conn(L, connfd);
}
}
}
}
if (n < 0)
{
/* TODO error handling */
}
}
return EXIT_SUCCESS;
} /*---------- end of function main ----------*/
Because your 's' contains line-feed symbol sent by telnet or whatever you use. Get one of trim implementations from http://lua-users.org/wiki/StringTrim and use s = 'You sent the string: "' .. trim(s) .. '" and then some stuff at the end.' or something like that.
Update: sorry about that, it is far more likely to be carriage return. But no matter, in view point of your question.
I am trying to write a C Code to do the same Job as:
netstat -vatp
List all Remote/Local Addresses and Processes using them. But I dunno which files should I be reading?
I tried looking into /proc/net/tcp and /proc/net/udp, but they don't have the process name or process identifier like netstat displays it!
Thanks.
You could check the source code http://freecode.com/projects/net-tools. Just download, unpack the bz2 file and you'll find the netstat.c source code
Quick analyse:
/proc/net/tcp for example has an inode tab, in /proc there is a subfolder for each of these inodes, which contains the information you need.
Some more analysing:
I think it's even worse. netstat just loops through the /proc directory and checks the contents of the numeric sub-directories to find the actual process matching the inode. Not sure as I'm just analysing
http://linux.die.net/man/5/proc is very nice reading :)
For your answer, see How can i match each /proc/net/tcp entry to each opened socket?
You could call the netstat application from within your code. Have a look at execve to capture stdout and stderr.
EDIT:
Since code says more than words:
IEFTask.h
#ifndef IEFTASK_H
#define IEFTASK_H
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <signal.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* MARK: Structure */
struct IEFTask {
const char **arguments; /* last argument should be NULL */
int standardInput;
void *callbackArgument;
void (*callback)(int term, char *out, size_t outLen,
char *err, size_t errLen, void *arg);
};
typedef struct IEFTask IEFTask;
/* MARK: Running */
int
IEFTaskRun(IEFTask *theTask);
#endif /* IEFTASK_H */
IEFTask.c
#include "IEFTask.h"
/* MARK: DECLARATION: Data Conversion */
char *
IEFTaskCreateBufferFromPipe(int fd, size_t *bufLen);
/* MARK: Running */
int
IEFTaskRun(IEFTask *myTask) {
pid_t pid;
int exitStatus, status;
int outPipe[2], errPipe[2];
assert(myTask != NULL);
/* Create stdout and stderr pipes */
{
status = pipe(outPipe);
if(status != 0) {
return -1;
}
status = pipe(errPipe);
if(status != 0) {
close(errPipe[0]);
close(errPipe[1]);
return -1;
}
}
/* Fork the process and wait pid */
{
pid = fork();
if(pid < 0) { /* error */
return -1;
} else if(pid > 0) { /* parent */
waitpid(pid, &exitStatus, 0);
exitStatus = WEXITSTATUS(exitStatus);
} else { /* child */
/* close unneeded pipes */
close(outPipe[0]);
close(errPipe[0]);
/* redirect stdout, stdin, stderr */
if(myTask->standardInput >= 0) {
close(STDIN_FILENO);
dup2(myTask->standardInput, STDIN_FILENO);
close(myTask->standardInput);
}
close(STDOUT_FILENO);
dup2(outPipe[1], STDOUT_FILENO);
close(outPipe[1]);
close(STDERR_FILENO);
dup2(errPipe[1], STDERR_FILENO);
close(errPipe[1]);
execve(myTask->arguments[0],
(char *const *)myTask->arguments, NULL);
exit(127);
}
}
/* Parent continues */
{
char *output, *error;
size_t outLen, errLen;
/* 127 = execve failed */
if(exitStatus == 127) {
close(errPipe[0]);
close(errPipe[1]);
close(outPipe[0]);
close(outPipe[1]);
return -1;
}
/* Read in data */
close(errPipe[1]);
close(outPipe[1]);
output = IEFTaskCreateBufferFromPipe(outPipe[0], &outLen);
error = IEFTaskCreateBufferFromPipe(errPipe[0], &errLen);
close(errPipe[0]);
close(outPipe[0]);
/* Call callback */
(*myTask->callback)(exitStatus,
output, outLen,
error, errLen, myTask->callbackArgument);
if(output) free(output);
if(error) free(error);
}
return 0;
}
/* MARK: Data Conversion */
#define READ_BUF_SIZE (128)
char *
IEFTaskCreateBufferFromPipe(int fd, size_t *bufLen) {
ssize_t totalRead = 0, nowRead;
char readBuffer[READ_BUF_SIZE], *myBuffer = NULL;
char *ptr;
while(1) {
nowRead = read(fd, readBuffer, READ_BUF_SIZE);
if(nowRead == -1) {
free(myBuffer);
return NULL;
} else if(nowRead == 0) {
break;
} else {
ptr = realloc(myBuffer, totalRead + nowRead);
if(ptr == NULL) {
free(myBuffer);
return NULL;
}
myBuffer = ptr;
memcpy(&(myBuffer[totalRead]), readBuffer, nowRead);
totalRead += nowRead;
}
}
if(bufLen) *bufLen = (size_t)totalRead;
return myBuffer;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "IEFTask.h"
void taskCallback(int term,
char *out, size_t outlen,
char *err, size_t errlen)
{
char *ptr;
printf("Task terminated: %d\n", term);
ptr = malloc(outlen + 1);
memcpy(ptr, out, outlen);
ptr[outlen] = '\0';
printf("***STDOUT:\n%s\n***END\n", ptr);
free(ptr);
ptr = malloc(errlen + 1);
memcpy(ptr, err, errlen);
ptr[errlen] = '\0';
printf("***STDERR:\n%s\n***END\n", ptr);
free(ptr);
}
int main() {
const char *arguments[] = {
"/bin/echo",
"Hello",
"World",
NULL
};
IEFTask myTask;
myTask.arguments = arguments;
myTask.standardInput = -1;
myTask.callback = &taskCallback;
int status;
status = IEFTaskRun(&myTask);
if(status != 0) {
printf("Failed: %s\n", strerror(errno));
}
return 0;
}
I am inexperienced with using C, and I need to use PCRE to get matches.
Here is a sample of my source code:
int test2()
{
const char *error;
int erroffset;
pcre *re;
int rc;
int i;
int ovector[OVECCOUNT];
char *regex = "From:([^#]+)#([^\r]+)";
char str[] = "From:regular.expressions#example.com\r\n"\
"From:exddd#43434.com\r\n"\
"From:7853456#exgem.com\r\n";
re = pcre_compile (
regex, /* the pattern */
0, /* default options */
&error, /* for error message */
&erroffset, /* for error offset */
0); /* use default character tables */
if (!re) {
printf("pcre_compile failed (offset: %d), %s\n", erroffset, error);
return -1;
}
rc = pcre_exec (
re, /* the compiled pattern */
0, /* no extra data - pattern was not studied */
str, /* the string to match */
strlen(str), /* the length of the string */
0, /* start at offset 0 in the subject */
0, /* default options */
ovector, /* output vector for substring information */
OVECCOUNT); /* number of elements in the output vector */
if (rc < 0) {
switch (rc) {
case PCRE_ERROR_NOMATCH:
printf("String didn't match");
break;
default:
printf("Error while matching: %d\n", rc);
break;
}
free(re);
return -1;
}
for (i = 0; i < rc; i++) {
printf("%2d: %.*s\n", i, ovector[2*i+1] - ovector[2*i], str + ovector[2*i]);
}
}
In this demo, the output is only:
0: From:regular.expressions#example.com
1: regular.expressions
2: example.com
I want to output all of the matches; how can I do that?
I use a class to wrap PCRE to make this easier, but after the pcre_exec, the ovector contains the substring indexes you need to find the matches within the original string.
So it would be something like:
#include <string>
#include <iostream>
#include "pcre.h"
int main (int argc, char *argv[])
{
const char *error;
int erroffset;
pcre *re;
int rc;
int i;
int ovector[100];
char *regex = "From:([^#]+)#([^\r]+)";
char str[] = "From:regular.expressions#example.com\r\n"\
"From:exddd#43434.com\r\n"\
"From:7853456#exgem.com\r\n";
re = pcre_compile (regex, /* the pattern */
PCRE_MULTILINE,
&error, /* for error message */
&erroffset, /* for error offset */
0); /* use default character tables */
if (!re)
{
printf("pcre_compile failed (offset: %d), %s\n", erroffset, error);
return -1;
}
unsigned int offset = 0;
unsigned int len = strlen(str);
while (offset < len && (rc = pcre_exec(re, 0, str, len, offset, 0, ovector, sizeof(ovector))) >= 0)
{
for(int i = 0; i < rc; ++i)
{
printf("%2d: %.*s\n", i, ovector[2*i+1] - ovector[2*i], str + ovector[2*i]);
}
offset = ovector[1];
}
return 1;
}
note: last parameter of pcre_exec() must be element-count, not sizeof() ! ( http://www.pcre.org/readme.txt )