Поверх lwip реализован простой raw-print сервер, который слушает порт 9100 и отсылает принятые
данные в принтер. Все работает хорошо до тех пор, пока в одно и то же время не поступают две и
более задач с планировщиков печати (спулеров) разных хостов. Суть вопроса: необходимо средствами
lwip разграничить доступ к принтеру, то есть обеспечить режим "занят" в момент обработки текущей задачи.
На данный момент есть эксперементальный код, который, собственно практически не работает...
Идея в том чтобы запомнить ip для текущей задачи (rawprint_remote_ip) и пока соединение не будет закрыто отправлять
все новые задачи через tcp_poll в ожидание.
Инициализация:
Код
void
rawprintd_init(void)
{
struct tcp_pcb *pcb;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprintd_init\n"));
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 9100);
pcb = tcp_listen(pcb);
tcp_accept(pcb, rawprint_accept);
}
rawprintd_init(void)
{
struct tcp_pcb *pcb;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprintd_init\n"));
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 9100);
pcb = tcp_listen(pcb);
tcp_accept(pcb, rawprint_accept);
}
Подтвержение:
CODE
static err_t
rawprint_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct rawprint_state *rs;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_accept 0x%08x\n", pcb));
/* Allocate memory for the structure that holds the state of the
connection. */
rs = (struct rawprint_state *)mem_malloc(sizeof(struct rawprint_state));
if (rs == NULL) {
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_accept: Out of memory\n"));
return ERR_MEM;
}
/* Initialize the structure. */
rs->retries = 0;
/* Tell TCP that this is the structure we wish to be passed for our
callbacks. */
tcp_arg(pcb, rs);
/* Tell TCP that we wish to be informed of incoming data by a call
to the http_recv() function. */
if (pcb->local_port == 9100)
{
if (rawprint_remote_ip == 0)
{
tcp_recv(pcb, rawprint_recv);
tcp_err(pcb, conn_err);
rawprint_remote_ip = pcb->remote_ip.addr;
rawprint_send_status(pcb, false);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_remote_ip %08x\n", rawprint_remote_ip));
}
else
{
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("go poll\n"));
tcp_poll(pcb, rawprint_poll, 1);
}
}
return ERR_OK;
}
rawprint_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct rawprint_state *rs;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_accept 0x%08x\n", pcb));
/* Allocate memory for the structure that holds the state of the
connection. */
rs = (struct rawprint_state *)mem_malloc(sizeof(struct rawprint_state));
if (rs == NULL) {
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_accept: Out of memory\n"));
return ERR_MEM;
}
/* Initialize the structure. */
rs->retries = 0;
/* Tell TCP that this is the structure we wish to be passed for our
callbacks. */
tcp_arg(pcb, rs);
/* Tell TCP that we wish to be informed of incoming data by a call
to the http_recv() function. */
if (pcb->local_port == 9100)
{
if (rawprint_remote_ip == 0)
{
tcp_recv(pcb, rawprint_recv);
tcp_err(pcb, conn_err);
rawprint_remote_ip = pcb->remote_ip.addr;
rawprint_send_status(pcb, false);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_remote_ip %08x\n", rawprint_remote_ip));
}
else
{
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("go poll\n"));
tcp_poll(pcb, rawprint_poll, 1);
}
}
return ERR_OK;
}
Прием данных:
CODE
static err_t
rawprint_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
tBoolean bSendStatus = false;
struct rawprint_state *rs;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_recv 0x%08x port %d\n", pcb, (unsigned int)pcb->local_port));
rs = arg;
if ((err == ERR_OK) && (p != NULL) && rs)
{
/* Inform TCP that we have taken the data. */
tcp_recved(pcb, p->tot_len);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_recv length %d bytes\n", p->tot_len));
if (p->len)
{
const unsigned char *pucData = p->payload;
switch(pcb->local_port)
{
case 9100:
if (!((pucData[0] == 0x00) && (p->len == 1)))
rawprint_printer_write(p);
if ((memcmp(g_pucReadPort, pucData, sizeof(g_pucReadPort)) == 0) && (p->len == sizeof(g_pucReadPort)))
bSendStatus = true;
break;
}
}
pbuf_free(p);
}
if (((err == ERR_OK) && (p == NULL)) || (bSendStatus))
{
rawprint_send_status(pcb, true);
}
return ERR_OK;
}
rawprint_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
tBoolean bSendStatus = false;
struct rawprint_state *rs;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_recv 0x%08x port %d\n", pcb, (unsigned int)pcb->local_port));
rs = arg;
if ((err == ERR_OK) && (p != NULL) && rs)
{
/* Inform TCP that we have taken the data. */
tcp_recved(pcb, p->tot_len);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_recv length %d bytes\n", p->tot_len));
if (p->len)
{
const unsigned char *pucData = p->payload;
switch(pcb->local_port)
{
case 9100:
if (!((pucData[0] == 0x00) && (p->len == 1)))
rawprint_printer_write(p);
if ((memcmp(g_pucReadPort, pucData, sizeof(g_pucReadPort)) == 0) && (p->len == sizeof(g_pucReadPort)))
bSendStatus = true;
break;
}
}
pbuf_free(p);
}
if (((err == ERR_OK) && (p == NULL)) || (bSendStatus))
{
rawprint_send_status(pcb, true);
}
return ERR_OK;
}
Опрос:
CODE
static err_t
rawprint_poll(void *arg, struct tcp_pcb *pcb)
{
struct rawprint_state *rs;
rs = arg;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_poll 0x%08x port %d\n", pcb, pcb->local_port));
/* printf("Polll\n");*/
if ((rs == NULL) && (pcb->state == ESTABLISHED)) {
/* printf("Null, close\n");*/
tcp_abort(pcb);
return ERR_ABRT;
} else {
if (rawprint_remote_ip == 0)
{
tcp_recv(pcb, rawprint_recv);
tcp_err(pcb, conn_err);
rawprint_remote_ip = pcb->remote_ip.addr;
rawprint_send_status(pcb, false);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_remote_ip %08x\n", rawprint_remote_ip));
}
}
return ERR_OK;
}
rawprint_poll(void *arg, struct tcp_pcb *pcb)
{
struct rawprint_state *rs;
rs = arg;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_poll 0x%08x port %d\n", pcb, pcb->local_port));
/* printf("Polll\n");*/
if ((rs == NULL) && (pcb->state == ESTABLISHED)) {
/* printf("Null, close\n");*/
tcp_abort(pcb);
return ERR_ABRT;
} else {
if (rawprint_remote_ip == 0)
{
tcp_recv(pcb, rawprint_recv);
tcp_err(pcb, conn_err);
rawprint_remote_ip = pcb->remote_ip.addr;
rawprint_send_status(pcb, false);
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("rawprint_remote_ip %08x\n", rawprint_remote_ip));
}
}
return ERR_OK;
}
Закрытие соединения:
CODE
/*-----------------------------------------------------------------------------------*/
static void
close_conn(struct tcp_pcb *pcb, struct rawprint_state *rs)
{
err_t err;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("Closing connection 0x%08x\n", pcb));
tcp_arg(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_recv(pcb, NULL);
if(rs) {
mem_free(rs);
}
if (pcb->remote_ip.addr == rawprint_remote_ip){
rawprint_remote_ip = 0;
}
err = tcp_close(pcb);
if(err != ERR_OK)
{
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("Error %d closing 0x%08x\n", err, pcb));
}
}
static void
close_conn(struct tcp_pcb *pcb, struct rawprint_state *rs)
{
err_t err;
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("Closing connection 0x%08x\n", pcb));
tcp_arg(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_recv(pcb, NULL);
if(rs) {
mem_free(rs);
}
if (pcb->remote_ip.addr == rawprint_remote_ip){
rawprint_remote_ip = 0;
}
err = tcp_close(pcb);
if(err != ERR_OK)
{
LWIP_DEBUGF(RAW_PRINTD_DEBUG, ("Error %d closing 0x%08x\n", err, pcb));
}
}
Я не совсем уверен в правильности вызова функции tcp_poll без tcp_recv в случае, когда задача уже запущена (rawprint_remote_ip != 0).
Есть у кого-нибудь идеи как реализовать правильно без буферизации, если это, конечно возможно?