serial.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * Serial back end (Windows-specific).
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <limits.h>
  7. #include "putty.h"
  8. #define SERIAL_MAX_BACKLOG 4096
  9. typedef struct Serial Serial;
  10. struct Serial {
  11. HANDLE port;
  12. struct handle *out, *in;
  13. Seat *seat;
  14. LogContext *logctx;
  15. int bufsize;
  16. long clearbreak_time;
  17. bool break_in_progress;
  18. Backend backend;
  19. };
  20. static void serial_terminate(Serial *serial)
  21. {
  22. if (serial->out) {
  23. handle_free(serial->out);
  24. serial->out = NULL;
  25. }
  26. if (serial->in) {
  27. handle_free(serial->in);
  28. serial->in = NULL;
  29. }
  30. if (serial->port != INVALID_HANDLE_VALUE) {
  31. if (serial->break_in_progress)
  32. ClearCommBreak(serial->port);
  33. CloseHandle(serial->port);
  34. serial->port = INVALID_HANDLE_VALUE;
  35. }
  36. }
  37. static size_t serial_gotdata(
  38. struct handle *h, const void *data, size_t len, int err)
  39. {
  40. Serial *serial = (Serial *)handle_get_privdata(h);
  41. if (err || len == 0) {
  42. const char *error_msg;
  43. /*
  44. * Currently, len==0 should never happen because we're
  45. * ignoring EOFs. However, it seems not totally impossible
  46. * that this same back end might be usable to talk to named
  47. * pipes or some other non-serial device, in which case EOF
  48. * may become meaningful here.
  49. */
  50. if (!err)
  51. error_msg = "End of file reading from serial device";
  52. else
  53. error_msg = "Error reading from serial device";
  54. serial_terminate(serial);
  55. seat_notify_remote_exit(serial->seat);
  56. logevent(serial->logctx, error_msg);
  57. seat_connection_fatal(serial->seat, "%s", error_msg);
  58. return 0;
  59. } else {
  60. return seat_stdout(serial->seat, data, len);
  61. }
  62. }
  63. static void serial_sentdata(struct handle *h, size_t new_backlog, int err,
  64. bool close)
  65. {
  66. Serial *serial = (Serial *)handle_get_privdata(h);
  67. if (err) {
  68. const char *error_msg = "Error writing to serial device";
  69. serial_terminate(serial);
  70. seat_notify_remote_exit(serial->seat);
  71. logevent(serial->logctx, error_msg);
  72. seat_connection_fatal(serial->seat, "%s", error_msg);
  73. } else {
  74. serial->bufsize = new_backlog;
  75. seat_sent(serial->seat, serial->bufsize);
  76. }
  77. }
  78. static char *serial_configure(Serial *serial, HANDLE serport, Conf *conf)
  79. {
  80. DCB dcb;
  81. COMMTIMEOUTS timeouts;
  82. /*
  83. * Set up the serial port parameters. If we can't even
  84. * GetCommState, we ignore the problem on the grounds that the
  85. * user might have pointed us at some other type of two-way
  86. * device instead of a serial port.
  87. */
  88. if (GetCommState(serport, &dcb)) {
  89. const char *str;
  90. /*
  91. * Boilerplate.
  92. */
  93. dcb.fBinary = true;
  94. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  95. dcb.fDsrSensitivity = false;
  96. dcb.fTXContinueOnXoff = false;
  97. dcb.fOutX = false;
  98. dcb.fInX = false;
  99. dcb.fErrorChar = false;
  100. dcb.fNull = false;
  101. dcb.fRtsControl = RTS_CONTROL_ENABLE;
  102. dcb.fAbortOnError = false;
  103. dcb.fOutxCtsFlow = false;
  104. dcb.fOutxDsrFlow = false;
  105. /*
  106. * Configurable parameters.
  107. */
  108. dcb.BaudRate = conf_get_int(conf, CONF_serspeed);
  109. logeventf(serial->logctx, "Configuring baud rate %lu",
  110. (unsigned long)dcb.BaudRate);
  111. dcb.ByteSize = conf_get_int(conf, CONF_serdatabits);
  112. logeventf(serial->logctx, "Configuring %u data bits",
  113. (unsigned)dcb.ByteSize);
  114. switch (conf_get_int(conf, CONF_serstopbits)) {
  115. case 2: dcb.StopBits = ONESTOPBIT; str = "1 stop bit"; break;
  116. case 3: dcb.StopBits = ONE5STOPBITS; str = "1.5 stop bits"; break;
  117. case 4: dcb.StopBits = TWOSTOPBITS; str = "2 stop bits"; break;
  118. default: return dupstr("Invalid number of stop bits "
  119. "(need 1, 1.5 or 2)");
  120. }
  121. logeventf(serial->logctx, "Configuring %s", str);
  122. switch (conf_get_int(conf, CONF_serparity)) {
  123. case SER_PAR_NONE: dcb.Parity = NOPARITY; str = "no"; break;
  124. case SER_PAR_ODD: dcb.Parity = ODDPARITY; str = "odd"; break;
  125. case SER_PAR_EVEN: dcb.Parity = EVENPARITY; str = "even"; break;
  126. case SER_PAR_MARK: dcb.Parity = MARKPARITY; str = "mark"; break;
  127. case SER_PAR_SPACE: dcb.Parity = SPACEPARITY; str = "space"; break;
  128. }
  129. logeventf(serial->logctx, "Configuring %s parity", str);
  130. switch (conf_get_int(conf, CONF_serflow)) {
  131. case SER_FLOW_NONE:
  132. str = "no";
  133. break;
  134. case SER_FLOW_XONXOFF:
  135. dcb.fOutX = dcb.fInX = true;
  136. str = "XON/XOFF";
  137. break;
  138. case SER_FLOW_RTSCTS:
  139. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  140. dcb.fOutxCtsFlow = true;
  141. str = "RTS/CTS";
  142. break;
  143. case SER_FLOW_DSRDTR:
  144. dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
  145. dcb.fOutxDsrFlow = true;
  146. str = "DSR/DTR";
  147. break;
  148. }
  149. logeventf(serial->logctx, "Configuring %s flow control", str);
  150. if (!SetCommState(serport, &dcb))
  151. return dupprintf("Configuring serial port: %s",
  152. win_strerror(GetLastError()));
  153. timeouts.ReadIntervalTimeout = 1;
  154. timeouts.ReadTotalTimeoutMultiplier = 0;
  155. timeouts.ReadTotalTimeoutConstant = 0;
  156. timeouts.WriteTotalTimeoutMultiplier = 0;
  157. timeouts.WriteTotalTimeoutConstant = 0;
  158. if (!SetCommTimeouts(serport, &timeouts))
  159. return dupprintf("Configuring serial timeouts: %s",
  160. win_strerror(GetLastError()));
  161. }
  162. return NULL;
  163. }
  164. /*
  165. * Called to set up the serial connection.
  166. *
  167. * Returns an error message, or NULL on success.
  168. *
  169. * Also places the canonical host name into `realhost'. It must be
  170. * freed by the caller.
  171. */
  172. static char *serial_init(const BackendVtable *vt, Seat *seat,
  173. Backend **backend_handle, LogContext *logctx,
  174. Conf *conf, const char *host, int port,
  175. char **realhost, bool nodelay, bool keepalive)
  176. {
  177. Serial *serial;
  178. HANDLE serport;
  179. char *err;
  180. char *serline;
  181. /* No local authentication phase in this protocol */
  182. seat_set_trust_status(seat, false);
  183. serial = snew(Serial);
  184. memset(serial, 0, sizeof(Serial));
  185. serial->port = INVALID_HANDLE_VALUE;
  186. serial->out = serial->in = NULL;
  187. serial->bufsize = 0;
  188. serial->break_in_progress = false;
  189. serial->backend.vt = vt;
  190. *backend_handle = &serial->backend;
  191. serial->seat = seat;
  192. serial->logctx = logctx;
  193. serline = conf_get_str(conf, CONF_serline);
  194. logeventf(serial->logctx, "Opening serial device %s", serline);
  195. /*
  196. * Munge the string supplied by the user into a Windows filename.
  197. *
  198. * Windows supports opening a few "legacy" devices (including
  199. * COM1-9) by specifying their names verbatim as a filename to
  200. * open. (Thus, no files can ever have these names. See
  201. * <http://msdn2.microsoft.com/en-us/library/aa365247.aspx>
  202. * ("Naming a File") for the complete list of reserved names.)
  203. *
  204. * However, this doesn't let you get at devices COM10 and above.
  205. * For that, you need to specify a filename like "\\.\COM10".
  206. * This is also necessary for special serial and serial-like
  207. * devices such as \\.\WCEUSBSH001. It also works for the "legacy"
  208. * names, so you can do \\.\COM1 (verified as far back as Win95).
  209. * See <http://msdn2.microsoft.com/en-us/library/aa363858.aspx>
  210. * (CreateFile() docs).
  211. *
  212. * So, we believe that prepending "\\.\" should always be the
  213. * Right Thing. However, just in case someone finds something to
  214. * talk to that doesn't exist under there, if the serial line
  215. * contains a backslash, we use it verbatim. (This also lets
  216. * existing configurations using \\.\ continue working.)
  217. */
  218. char *serfilename =
  219. dupprintf("%s%s", strchr(serline, '\\') ? "" : "\\\\.\\", serline);
  220. serport = CreateFile(serfilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  221. OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  222. if (serport == INVALID_HANDLE_VALUE) {
  223. err = dupprintf("Opening '%s': %s",
  224. serfilename, win_strerror(GetLastError()));
  225. sfree(serfilename);
  226. return err;
  227. }
  228. sfree(serfilename);
  229. err = serial_configure(serial, serport, conf);
  230. if (err)
  231. return err;
  232. serial->port = serport;
  233. serial->out = handle_output_new(serport, serial_sentdata, serial,
  234. HANDLE_FLAG_OVERLAPPED);
  235. serial->in = handle_input_new(serport, serial_gotdata, serial,
  236. HANDLE_FLAG_OVERLAPPED |
  237. HANDLE_FLAG_IGNOREEOF |
  238. HANDLE_FLAG_UNITBUFFER);
  239. *realhost = dupstr(serline);
  240. /*
  241. * Specials are always available.
  242. */
  243. seat_update_specials_menu(serial->seat);
  244. return NULL;
  245. }
  246. static void serial_free(Backend *be)
  247. {
  248. Serial *serial = container_of(be, Serial, backend);
  249. serial_terminate(serial);
  250. expire_timer_context(serial);
  251. sfree(serial);
  252. }
  253. static void serial_reconfig(Backend *be, Conf *conf)
  254. {
  255. Serial *serial = container_of(be, Serial, backend);
  256. serial_configure(serial, serial->port, conf);
  257. /*
  258. * FIXME: what should we do if that call returned a non-NULL error
  259. * message?
  260. */
  261. }
  262. /*
  263. * Called to send data down the serial connection.
  264. */
  265. static void serial_send(Backend *be, const char *buf, size_t len)
  266. {
  267. Serial *serial = container_of(be, Serial, backend);
  268. if (serial->out == NULL)
  269. return;
  270. serial->bufsize = handle_write(serial->out, buf, len);
  271. }
  272. /*
  273. * Called to query the current sendability status.
  274. */
  275. static size_t serial_sendbuffer(Backend *be)
  276. {
  277. Serial *serial = container_of(be, Serial, backend);
  278. return serial->bufsize;
  279. }
  280. /*
  281. * Called to set the size of the window
  282. */
  283. static void serial_size(Backend *be, int width, int height)
  284. {
  285. /* Do nothing! */
  286. return;
  287. }
  288. static void serbreak_timer(void *ctx, unsigned long now)
  289. {
  290. Serial *serial = (Serial *)ctx;
  291. if (now == serial->clearbreak_time && serial->port) {
  292. ClearCommBreak(serial->port);
  293. serial->break_in_progress = false;
  294. logevent(serial->logctx, "Finished serial break");
  295. }
  296. }
  297. /*
  298. * Send serial special codes.
  299. */
  300. static void serial_special(Backend *be, SessionSpecialCode code, int arg)
  301. {
  302. Serial *serial = container_of(be, Serial, backend);
  303. if (serial->port && code == SS_BRK) {
  304. logevent(serial->logctx, "Starting serial break at user request");
  305. SetCommBreak(serial->port);
  306. /*
  307. * To send a serial break on Windows, we call SetCommBreak
  308. * to begin the break, then wait a bit, and then call
  309. * ClearCommBreak to finish it. Hence, I must use timing.c
  310. * to arrange a callback when it's time to do the latter.
  311. *
  312. * SUS says that a default break length must be between 1/4
  313. * and 1/2 second. FreeBSD apparently goes with 2/5 second,
  314. * and so will I.
  315. */
  316. serial->clearbreak_time =
  317. schedule_timer(TICKSPERSEC * 2 / 5, serbreak_timer, serial);
  318. serial->break_in_progress = true;
  319. }
  320. return;
  321. }
  322. /*
  323. * Return a list of the special codes that make sense in this
  324. * protocol.
  325. */
  326. static const SessionSpecial *serial_get_specials(Backend *be)
  327. {
  328. static const SessionSpecial specials[] = {
  329. {"Break", SS_BRK},
  330. {NULL, SS_EXITMENU}
  331. };
  332. return specials;
  333. }
  334. static bool serial_connected(Backend *be)
  335. {
  336. return true; /* always connected */
  337. }
  338. static bool serial_sendok(Backend *be)
  339. {
  340. return true;
  341. }
  342. static void serial_unthrottle(Backend *be, size_t backlog)
  343. {
  344. Serial *serial = container_of(be, Serial, backend);
  345. if (serial->in)
  346. handle_unthrottle(serial->in, backlog);
  347. }
  348. static bool serial_ldisc(Backend *be, int option)
  349. {
  350. /*
  351. * Local editing and local echo are off by default.
  352. */
  353. return false;
  354. }
  355. static void serial_provide_ldisc(Backend *be, Ldisc *ldisc)
  356. {
  357. /* This is a stub. */
  358. }
  359. static int serial_exitcode(Backend *be)
  360. {
  361. Serial *serial = container_of(be, Serial, backend);
  362. if (serial->port != INVALID_HANDLE_VALUE)
  363. return -1; /* still connected */
  364. else
  365. /* Exit codes are a meaningless concept with serial ports */
  366. return INT_MAX;
  367. }
  368. /*
  369. * cfg_info for Serial does nothing at all.
  370. */
  371. static int serial_cfg_info(Backend *be)
  372. {
  373. return 0;
  374. }
  375. const BackendVtable serial_backend = {
  376. .init = serial_init,
  377. .free = serial_free,
  378. .reconfig = serial_reconfig,
  379. .send = serial_send,
  380. .sendbuffer = serial_sendbuffer,
  381. .size = serial_size,
  382. .special = serial_special,
  383. .get_specials = serial_get_specials,
  384. .connected = serial_connected,
  385. .exitcode = serial_exitcode,
  386. .sendok = serial_sendok,
  387. .ldisc_option_state = serial_ldisc,
  388. .provide_ldisc = serial_provide_ldisc,
  389. .unthrottle = serial_unthrottle,
  390. .cfg_info = serial_cfg_info,
  391. .id = "serial",
  392. .displayname_tc = "Serial",
  393. .displayname_lc = "serial",
  394. .protocol = PROT_SERIAL,
  395. .serial_parity_mask = ((1 << SER_PAR_NONE) |
  396. (1 << SER_PAR_ODD) |
  397. (1 << SER_PAR_EVEN) |
  398. (1 << SER_PAR_MARK) |
  399. (1 << SER_PAR_SPACE)),
  400. .serial_flow_mask = ((1 << SER_FLOW_NONE) |
  401. (1 << SER_FLOW_XONXOFF) |
  402. (1 << SER_FLOW_RTSCTS) |
  403. (1 << SER_FLOW_DSRDTR)),
  404. };