On Tuesday, November 7, 2017 at 12:55:47 AM UTC-8, Ben Noordhuis wrote:
>
> On Tue, Nov 7, 2017 at 2:23 AM, Russell Haley <[email protected]
> <javascript:>> wrote:
> > On Monday, November 6, 2017 at 12:14:18 PM UTC-8, Russell Haley wrote:
> >> On Monday, November 6, 2017 at 11:49:43 AM UTC-8, Ben Noordhuis wrote:
> >>>
> >>> On Mon, Nov 6, 2017 at 7:56 PM, Russell Haley <[email protected]>
> wrote:
> >>> > Hello,
> >>> >
> >>> > I'm new to C patterns and I am experimenting with libuv to write a
> >>> > simulator. The idea is to create a context struct to be passed
> around
> >>> > as a
> >>> > pointer/handle to various timed and event based callback functions.
> I
> >>> > would
> >>> > like this simulator to have a "heartbeat" that sends UDP every x
> >>> > period, as
> >>> > well as respond to UDP messages received on a different port. I
> would
> >>> > like
> >>> > the system to decides at runtime if there are flags in the context
> that
> >>> > block it from sending (i.e. handle->send=0;).
> >>> >
> >>> > For bonus points, I would like to be able to start a TCP based
> module
> >>> > if I
> >>> > receive a certain message on the UDP receive port and then stop it
> once
> >>> > the
> >>> > routine completes. I am hoping I can just drop a routine on the
> default
> >>> > loop
> >>> > (from within my uv_udp_recv_cb) for processing until completion
> which
> >>> > would
> >>> > be signaled in a TCP callback (haven't delved into the TCP stuff
> >>> > yet...).
> >>> >
> >>> > After about 1 hour of searching I haven't found any examples of what
> I
> >>> > am
> >>> > trying to do. Most of the example patterns are very simplistic. This
> >>> > dearth
> >>> > of information leads me to one of two conclusions: 1) I am trying to
> do
> >>> > something the wrong way or 2) nobody in the entirety of using libuv
> has
> >>> > ever
> >>> > ever ever tried to do what I am attempting now. I assume the problem
> is
> >>> > the
> >>> > former. ;)
> >>> >
> >>> > What I have so far:
> >>> >
> >>> > - An example udp listener from the docs. It listens faithfully on
> the
> >>> > port I
> >>> > assign.
> >>> > - A udp client, again from the docs. My first kick simply sends a
> >>> > message
> >>> > and then exists . My next planned attempt was to use a timer to send
> >>> > the
> >>> > information repeatedly. I have realized that the timer callback
> needs
> >>> > to
> >>> > have my context handle, which prompted this question. I will finish
> my
> >>> > example code and then post it here while awaiting a possible answer.
> >>> >
> >>> > Please let me know if I can provide some more background (context?
> tee
> >>> > hee).
> >>> >
> >>> > Regards,
> >>> >
> >>> > Russ
> >>>
> >>> It's not entirely clear to me what you want to accomplish but if you
> >>> want to attach state/context to a handle or request, you can use the
> >>> handle->data and req->data fields. or embed them in another struct and
> >>> use container_of() to look up the embedder. You can find a
> >>> container_of() definition in the libuv sources.
> >>
> >>
> >> Thanks so much for responding. I just stumbled over your answer in uv.h
> >> (described in UV_HANDLE_FIELDS) and then found it in the documentation.
> I
> >> missed the context section at the bottom of the basics page. :(
> >>
> >> Thanks for the answer and sorry for the noise!
> >>
> >> Russ
> >
> >
> > Okay, a little more noise. I'm getting a segmentation fault in
> libuv.so.1
> > that I can't seem to debug (unsurprising with my limited gdb skills).
> The
> > following code is my udp client. It's supposed to:
> > 1) Set up the context in main()
> > 2) Start a timer to tick once, then once per second.
> > 3) On each tick, send a udp message and augment the counter.
> > 4) If the counter is 10, stop.
> >
> > udp-spammer.c:
> >
> > #include <unistd.h>
> > #include <stdio.h>
> > #include <uv.h>
> > #include <stdlib.h>
> > #include <string.h>
> >
> > #define UDP_SEND_PORT 49284
> > #define UDP_REC_PORT 49280
> >
> > #define VMDS_ADDR "127.0.0.1"
> > #define TRU_ADDR "127.0.0.1"
> > #define ON 1
> > #define OFF 0
> >
> > typedef struct context_t {
> > uv_udp_t* send_ctx;
> > int count;
> > int send;
> > uv_buf_t* message;
> > }context_t;
> >
> >
> > static void s_alloc_cb(uv_handle_t* handle, size_t suggested_size,
> uv_buf_t*
> > buf) {
> > buf->base = malloc(suggested_size);
> > buf->len = suggested_size;
> > }
> >
> > void on_send (uv_udp_send_t* req, int status)
> > {
> > printf("Status: %d\n",status);
> > }
> >
> > uv_buf_t make_sd_msg(char* msg)
> > {
> > uv_buf_t buf = uv_buf_init(msg, strlen(msg));
> > return buf;
> > }
> >
> > void spam(uv_timer_t* h)
> > {
> > context_t* ctx = (context_t*)h->data;
> > if(ctx == NULL)
> > {
> > printf("Esplode!");
> > exit(1);
> > }
> >
> > struct sockaddr_in broadcast_addr;
> > uv_ip4_addr(VMDS_ADDR, 0, &broadcast_addr);
> > uv_udp_bind(ctx->send_ctx, (const struct sockaddr *)&broadcast_addr,
> 0);
> >
> > uv_udp_send_t send_req;
> >
> > struct sockaddr_in remote_addr;
> > uv_ip4_addr(TRU_ADDR, UDP_REC_PORT, &remote_addr);
> > uv_udp_send(&send_req, ctx->send_ctx, ctx->message, 1, (const struct
> > sockaddr *)&remote_addr, on_send);
> >
> > ctx->count++;
> > if(ctx->count >= 10)
> > {
> > uv_timer_stop(h);
> > }
> > }
> >
> > int main() {
> >
> > uv_loop_t *loop;
> > uv_timer_t timed;
> > context_t ctx;
> >
> > loop = uv_default_loop();
> >
> > ctx.send = 1;
> > ctx.count = 0;
> > uv_buf_t msg = make_sd_msg("Hello Lucy!\n\0");
> > ctx.message = &msg;
> > uv_udp_t snd;
> > uv_udp_init(loop, &snd);
> > ctx.send_ctx = &snd;
> >
> > timed.data = &ctx;
> >
> > uv_timer_init(loop, &timed);
> > uv_timer_start(&timed, spam, 0,1000);
> >
> > return uv_run(loop, UV_RUN_DEFAULT);
> > }
> >
> >
> >
> > So far, it sends the first UDP message and then I get a SIGSEV in
> > libuv.so.1. bt isn't telling me much that I can use:
> >
> > 0xb7fad4bd in ?? () from /usr/lib/i386-linux-gnu/libuv.so.1
> > (gdb) bt
> > #0 0xb7fad4bd in ?? () from /usr/lib/i386-linux-gnu/libuv.so.1
> > #1 0xb7fad852 in ?? () from /usr/lib/i386-linux-gnu/libuv.so.1
> > #2 0xb7fa0be9 in uv_run () from /usr/lib/i386-linux-gnu/libuv.so.1
> > #3 0x08048ad4 in main () at udp-spammer.c:86
> >
> > Any help would be grand.
> >
> > Thanks!
> > Russ
>
> The `uv_udp_t send_req` in spam() is stack-allocated. It goes out of
> scope and gets clobbered the moment that function returns. Allocate
> it statically or on the heap instead.
>
> Build libuv from source if you want debug symbols, or check if your
> distro has a libuv-dbg package or installs debug symbols separately
> (e.g, debuginfo-install on Fedora.)
>
Thanks for your help Ben. Here is the working code:
#include <unistd.h>
#include <stdio.h>
#include <uv.h>
#include <stdlib.h>
#include <string.h>
#define UDP_SEND_PORT 49284
#define UDP_REC_PORT 49280
#define VMDS_ADDR "127.0.0.1"
#define TRU_ADDR "127.0.0.1"
#define ON 1
#define OFF 0
typedef struct context_t {
uv_udp_t* send_ctx;
uv_udp_send_t* send_req;
int count;
int send;
uv_buf_t* message;
}context_t;
static void s_alloc_cb(uv_handle_t* handle, size_t suggested_size,
uv_buf_t* buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
void on_send (uv_udp_send_t* req, int status)
{
printf("Status: %d\n",status);
}
uv_buf_t make_sd_msg(char* msg, size_t len)
{
uv_buf_t buf = uv_buf_init(msg, len);
return buf;
}
void spam(uv_timer_t* h)
{
context_t* ctx = (context_t*)h->data;
if(ctx == NULL)
{
printf("Esplode!");
exit(1);
}
if(ctx->count == 10)
{
//free(ctx->message);
char* gn = "Good Night!";
*ctx->message = make_sd_msg(gn,strlen(gn));
}
else if(ctx->count == 11)
{
uv_timer_stop(h);
return;
}
struct sockaddr_in broadcast_addr;
uv_ip4_addr(VMDS_ADDR, 0, &broadcast_addr);
uv_udp_bind(ctx->send_ctx, (const struct sockaddr *)&broadcast_addr, 0);
struct sockaddr_in remote_addr;
uv_ip4_addr(TRU_ADDR, UDP_REC_PORT, &remote_addr);
uv_udp_send(ctx->send_req, ctx->send_ctx, ctx->message, 1, (const
struct sockaddr *)&remote_addr, on_send);
ctx->count++;
}
int main() {
int res = -1;
int restart = 1;
uv_loop_t *loop;
uv_timer_t timed;
context_t ctx;
uv_udp_t udp;
uv_udp_send_t send_req;
loop = uv_default_loop();
ctx.send = 1;
ctx.count = 0;
char* msg = "Hello Sally!\n\0";
uv_buf_t mbuf = make_sd_msg(msg, strlen(msg));
ctx.message = &mbuf;
uv_udp_init(loop, &udp);
ctx.send_ctx = &udp;
ctx.send_req = &send_req;
timed.data = &ctx;
uv_timer_init(loop, &timed);
uv_timer_start(&timed, spam, 0,1000);
res = uv_run(loop, UV_RUN_DEFAULT);
if(restart)
{
ctx.count = 0;
char* msg = "Hello Sally!\n\0";
uv_buf_t mbuf = make_sd_msg(msg, strlen(msg));
ctx.message = &mbuf;
}
uv_timer_start(&timed, spam, 0,1000);
res = uv_run(loop, UV_RUN_DEFAULT);
return res;
}
and the server side code:
#include <unistd.h>
#include <stdio.h>
#include "uv.h"
#include <stdlib.h>
#define UDP_SEND_PORT 49284
#define UDP_REC_PORT 49280
#define VMDS_ADDR "127.0.0.1"
#define ON 1
#define OFF 0
uv_loop_t *loop;
uv_udp_t send_socket;
uv_udp_t recv_socket;
void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const
struct sockaddr *addr, unsigned flags) {
if (nread < 0) {
fprintf(stderr, "Read error %s\n", uv_err_name(nread));
uv_close((uv_handle_t*) req, NULL);
free(buf->base);
return;
}
else if(nread == 0)
{
fprintf(stderr,"Zero bytes read.");
return;
}
char sender[17] = { 0 };
uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
fprintf(stderr, "Recv from %s\n", sender);
printf("Bytes read: %d\n",nread);
printf("%s\n",buf->base);
free(buf->base);
}
static void s_alloc_cb(uv_handle_t* handle, size_t suggested_size,
uv_buf_t* buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
void on_send (uv_udp_send_t* req, int status)
{
}
uv_buf_t make_sd_msg(char* msg)
{
uv_buf_t buf = uv_buf_init(msg, sizeof(msg));
return buf;
}
int stop()
{
//uv_udp_recv_stop(req);
}
int main() {
loop = uv_default_loop();
uv_udp_init(loop, &recv_socket);
struct sockaddr_in recv_addr;
uv_ip4_addr(VMDS_ADDR, UDP_REC_PORT, &recv_addr);
uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr,
UV_UDP_REUSEADDR);
uv_udp_recv_start(&recv_socket, s_alloc_cb, on_read);
return uv_run(loop, UV_RUN_DEFAULT);
}
and a generic makefile that worked for both client and server (changing the
module name). I removed my paths so not sure if it still works.
src = $(wildcard *.c)
obj = $(src:.c=.o)
MODULE = uv-client
CFLAGS = -ggdb
LDFLAGS = -luv
$(MODULE): $(obj)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean:
rm -f $(obj) $(MODULE)
--
You received this message because you are subscribed to the Google Groups
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.