I have a weird problem with the posix socket api in vxworks 5.5.1. The code is trivial and probably not interesting (added below), but the gist of it is: When calling socket()
and bind()
in a separate function from the one calling recvfrom()
, a pagefault occurs at the recvfrom()
call. If everything is done in the same function it works fine. Note that the fault happens immediately when calling recvfrom()
, not when a packet arrives.
Does VxWorks use the stack in some unexpected way for this API?
Edit: Added some code. The te_serve1()
function works fine, but te_serve_one()
(using helper functions) do not.
#include <taskLib.h>
#include <sysLib.h>
#include <string.h>
#include <taskLib.h>
#include <stdlib.h>
#include <stdio.h>
#include <types.h>
#include <sys/socket.h>
#include <sockLib.h>
#include <netinet/in.h>
#ifdef DEBUG
#define DP(...) printf(__VA_ARGS__)
#else
#define DP(...) do { } while(0)
#endif
#define LLB(l, b) ((l & (0x000000FF << (b*8))) >> b*8)
struct msg_log {
unsigned long src;
int size;
};
static int setup(short port)
{
int err = 0;
struct sockaddr_in addr;
int sock;
DP("socket()\n");
err = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (err < 0)
return err;
sock = err;
addr.sin_family = AF_INET;
addr.sin_port = htons(7357);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
DP("bind()\n");
err = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (err) {
close(sock);
return err;
}
return sock;
}
static int serve(int sock, struct msg_log *log)
{
char buf[32];
struct sockaddr_in caddr;
int caddr_len = sizeof(caddr);
int ret;
int len;
bzero((char *)&caddr, sizeof(caddr));
DP("recvfrom()\n");
ret = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *) &caddr, &caddr_len);
if (ret < 0) return ret;
len = ret;
if (log) {
DP("log()");
log->src = caddr.sin_addr.s_addr;
log->size = len;
}
DP("sendto()");
ret = sendto(sock, (caddr_t) &buf, len, 0, (struct sockaddr *) &caddr, caddr_len);
return ret;
}
static void serve_multiple(int sock)
{
for (;;)
if (serve(sock, NULL) < 0) break;
}
int te_serve_one(void)
{
DP("%s\n", __FUNCTION__);
int sock;
struct msg_log log; /* = {0}; */
int ret = 0;
short port = 1234;
DP("setup()\n");
sock = setup(port);
if (sock < 0)
goto out;
sock = ret;
ret = serve(sock, &log);
if(ret < 0)
goto tidy;
DP("report:\n");
printf("Echo'd %d byte to %lu.%lu.%lu.%lu\n",
log.size,
LLB(log.src, 0),
LLB(log.src, 1),
LLB(log.src, 2),
LLB(log.src, 3));
tidy:
DP("close()");
close(sock);
out:
return ret;
}
int te_serve1(short port)
{
int ret = 0;
int sock;
struct sockaddr_in addr;
char buf[32];
struct sockaddr_in caddr;
int caddr_len = sizeof(caddr);
int len;
DP("socket()\n");
ret = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ret < 0)
goto out;
sock = ret;
/* host addr */
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
DP("bind()\n");
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret)
goto tidy;
/* serve */
for (;;) {
DP("recvfrom()\n");
ret = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *) &caddr, &caddr_len);
if (ret < 0)
break;
len = ret;
if (len >= 4 && !strncmp(buf, "kill", 4)) {
ret = 0;
break;
}
DP("sendto()\n");
ret = sendto(sock, (caddr_t) &buf, len, 0,
(struct sockaddr *) &caddr, caddr_len);
printf("Echo'd %d byte to %lu.%lu.%lu.%lu\n",
len,
LLB(caddr.sin_addr.s_addr, 0), LLB(caddr.sin_addr.s_addr, 1),
LLB(caddr.sin_addr.s_addr, 2), LLB(caddr.sin_addr.s_addr, 3));
}
tidy:
DP("close()");
close(sock);
out:
return ret;
}
Looking at the optimized assembly, I realized that the sock
variable got overwritten by ret
, which at that point is unused and initialized to zero. Splendid.